@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,673 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prototype_tetrahedrize_mesh.js
|
|
3
|
+
*
|
|
4
|
+
* Drag-and-drop a GLTF/GLB file. Every mesh inside the scene is converted to a
|
|
5
|
+
* BinaryTopology, tetrahedralized via `compute_tetrahedral_mesh_from_surface`,
|
|
6
|
+
* and rendered as a pile of slightly shrunken tetrahedra so the volumetric
|
|
7
|
+
* structure is visible. Each input geometry is shown in its own solid colour
|
|
8
|
+
* to make them easy to tell apart.
|
|
9
|
+
*
|
|
10
|
+
* This module is intentionally self-contained — no engine harness, no ECS,
|
|
11
|
+
* just bare three.js + the tetrahedralization pipeline.
|
|
12
|
+
*
|
|
13
|
+
* Reference prototypes:
|
|
14
|
+
* - prototypeTetrahedraBuilder.js (tet mesh creation patterns)
|
|
15
|
+
* - prototypeMeshSimplification.js (raw three.js bootstrap, drop-file handling style)
|
|
16
|
+
* - prototypeBinaryTopology.js (BinaryTopology construction from indexed geometry)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
AmbientLight,
|
|
21
|
+
BufferAttribute,
|
|
22
|
+
BufferGeometry,
|
|
23
|
+
DirectionalLight,
|
|
24
|
+
Float32BufferAttribute,
|
|
25
|
+
Group,
|
|
26
|
+
Mesh,
|
|
27
|
+
MeshStandardMaterial,
|
|
28
|
+
PerspectiveCamera,
|
|
29
|
+
Scene,
|
|
30
|
+
Vector3 as ThreeVector3,
|
|
31
|
+
WebGLRenderer
|
|
32
|
+
} from "three";
|
|
33
|
+
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
34
|
+
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
35
|
+
import { BinaryTopology } from "../topology/struct/binary/BinaryTopology.js";
|
|
36
|
+
import {
|
|
37
|
+
bt_mesh_from_indexed_geometry
|
|
38
|
+
} from "../topology/struct/binary/io/bt_mesh_from_indexed_geometry.js";
|
|
39
|
+
import {
|
|
40
|
+
triangle_mesh_compute_signed_volume
|
|
41
|
+
} from "../triangle/triangle_mesh_compute_signed_volume.js";
|
|
42
|
+
import { compute_tetrahedral_mesh_from_surface } from "./compute_tetrahedral_mesh_from_surface.js";
|
|
43
|
+
import { compute_tetrahedron_quality } from "./compute_tetrahedron_quality.js";
|
|
44
|
+
import { compute_tetrahedron_volume } from "./compute_tetrahedron_volume.js";
|
|
45
|
+
import { tetrahedral_mesh_improve_quality } from "./tetrahedral_mesh_improve_quality.js";
|
|
46
|
+
import { TetrahedralMesh } from "./TetrahedralMesh.js";
|
|
47
|
+
|
|
48
|
+
// Quality threshold below which we count a tet as a sliver. Matches the
|
|
49
|
+
// usual "shape is starting to hurt simulation conditioning" cutoff for the
|
|
50
|
+
// radius-ratio metric.
|
|
51
|
+
const SLIVER_QUALITY_THRESHOLD = 0.05;
|
|
52
|
+
|
|
53
|
+
// Sliver-removal driver config. Currently OFF by default because the
|
|
54
|
+
// driver isn't optimised for interactive use yet: on a 6,500-tet Suzanne
|
|
55
|
+
// (and similar) it takes ~50 seconds per pass, which would freeze the UI
|
|
56
|
+
// on every drop. The main hotspot is `tetrahedral_mesh_vertex_is_boundary`
|
|
57
|
+
// inside the smoothing pass — it scans every tet in the mesh per vertex.
|
|
58
|
+
// Builds a vertex→tet adjacency cache once per pass to replace it.
|
|
59
|
+
//
|
|
60
|
+
// When enabled, the driver halves the sliver count on Suzanne and
|
|
61
|
+
// commits ~200 3-2 flips; smoothing is a no-op on closed-surface meshes
|
|
62
|
+
// because every vertex is on the boundary. Toggle this to true if you
|
|
63
|
+
// want the BEFORE → AFTER numbers logged in the per-mesh console line.
|
|
64
|
+
const ENABLE_IMPROVE_QUALITY = false;
|
|
65
|
+
const IMPROVE_TARGET_QUALITY = 0.05; // sliver cutoff only — keep the workload small
|
|
66
|
+
const IMPROVE_MAX_PASSES = 1;
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Visual / behaviour tunables
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
const BACKGROUND_COLOR = 0x202428;
|
|
73
|
+
const EXPLODE_FACTOR = 0.88; // scale each tet toward its centroid; <1 reveals gaps
|
|
74
|
+
const COLOR_SATURATION = 0.62;
|
|
75
|
+
const COLOR_VALUE = 0.92;
|
|
76
|
+
const COLOR_HUE_STEP = 0.61803398875; // golden-ratio conjugate → good separation
|
|
77
|
+
const CAMERA_FIT_PADDING = 1.5;
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Colour helpers
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Standard HSV → packed 0xRRGGBB conversion.
|
|
85
|
+
*
|
|
86
|
+
* @param {number} h hue in [0,1)
|
|
87
|
+
* @param {number} s saturation in [0,1]
|
|
88
|
+
* @param {number} v value in [0,1]
|
|
89
|
+
* @returns {number}
|
|
90
|
+
*/
|
|
91
|
+
function hsv_to_rgb_hex(h, s, v) {
|
|
92
|
+
const i = Math.floor(h * 6);
|
|
93
|
+
const f = h * 6 - i;
|
|
94
|
+
const p = v * (1 - s);
|
|
95
|
+
const q = v * (1 - f * s);
|
|
96
|
+
const t = v * (1 - (1 - f) * s);
|
|
97
|
+
|
|
98
|
+
let r, g, b;
|
|
99
|
+
switch (i % 6) {
|
|
100
|
+
case 0: r = v; g = t; b = p; break;
|
|
101
|
+
case 1: r = q; g = v; b = p; break;
|
|
102
|
+
case 2: r = p; g = v; b = t; break;
|
|
103
|
+
case 3: r = p; g = q; b = v; break;
|
|
104
|
+
case 4: r = t; g = p; b = v; break;
|
|
105
|
+
case 5: r = v; g = p; b = q; break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return (Math.round(r * 255) << 16) | (Math.round(g * 255) << 8) | Math.round(b * 255);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Pick a visually distinct colour for the i-th geometry. Golden-angle hue
|
|
113
|
+
* stepping spreads neighbouring indices far apart in colour space.
|
|
114
|
+
*
|
|
115
|
+
* @param {number} i
|
|
116
|
+
* @returns {number} 0xRRGGBB
|
|
117
|
+
*/
|
|
118
|
+
function color_for_index(i) {
|
|
119
|
+
return hsv_to_rgb_hex((i * COLOR_HUE_STEP) % 1, COLOR_SATURATION, COLOR_VALUE);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Exploded-tet geometry construction
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Emit a single triangle as 3 positions + 3 (flat) normals into the output
|
|
128
|
+
* arrays at `write_offset`. The vertex order is chosen so the normal points
|
|
129
|
+
* away from `opposite` — guaranteeing outward-facing tet faces regardless of
|
|
130
|
+
* the Delaunay output's vertex winding.
|
|
131
|
+
*
|
|
132
|
+
* Returns the new write offset (always advances by 9).
|
|
133
|
+
*/
|
|
134
|
+
function emit_face(positions, normals, write_offset, p0, p1, p2, opposite) {
|
|
135
|
+
const ex = p1[0] - p0[0], ey = p1[1] - p0[1], ez = p1[2] - p0[2];
|
|
136
|
+
const fx = p2[0] - p0[0], fy = p2[1] - p0[1], fz = p2[2] - p0[2];
|
|
137
|
+
|
|
138
|
+
let nx = ey * fz - ez * fy;
|
|
139
|
+
let ny = ez * fx - ex * fz;
|
|
140
|
+
let nz = ex * fy - ey * fx;
|
|
141
|
+
|
|
142
|
+
// If normal points toward the opposite vertex, flip the winding.
|
|
143
|
+
const dx = p0[0] - opposite[0], dy = p0[1] - opposite[1], dz = p0[2] - opposite[2];
|
|
144
|
+
if (nx * dx + ny * dy + nz * dz < 0) {
|
|
145
|
+
nx = -nx; ny = -ny; nz = -nz;
|
|
146
|
+
const tmp = p1; p1 = p2; p2 = tmp;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const len = Math.sqrt(nx * nx + ny * ny + nz * nz) || 1;
|
|
150
|
+
nx /= len; ny /= len; nz /= len;
|
|
151
|
+
|
|
152
|
+
positions[write_offset + 0] = p0[0]; positions[write_offset + 1] = p0[1]; positions[write_offset + 2] = p0[2];
|
|
153
|
+
positions[write_offset + 3] = p1[0]; positions[write_offset + 4] = p1[1]; positions[write_offset + 5] = p1[2];
|
|
154
|
+
positions[write_offset + 6] = p2[0]; positions[write_offset + 7] = p2[1]; positions[write_offset + 8] = p2[2];
|
|
155
|
+
|
|
156
|
+
for (let k = 0; k < 3; k++) {
|
|
157
|
+
normals[write_offset + k * 3 + 0] = nx;
|
|
158
|
+
normals[write_offset + k * 3 + 1] = ny;
|
|
159
|
+
normals[write_offset + k * 3 + 2] = nz;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return write_offset + 9;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Build a flat-shaded triangle geometry where each tetrahedron is rendered
|
|
167
|
+
* as four outward-facing triangles, with the tet's vertices contracted
|
|
168
|
+
* toward its centroid by `shrink`. The contraction creates visible gaps
|
|
169
|
+
* between adjacent tets so the volumetric tessellation is obvious.
|
|
170
|
+
*
|
|
171
|
+
* @param {TetrahedralMesh} tet_mesh
|
|
172
|
+
* @param {Float32Array|number[]} points flat (x,y,z) positions array
|
|
173
|
+
* @param {number} shrink (0,1] — 1 = touching tets, 0.85 = clear gaps
|
|
174
|
+
* @returns {BufferGeometry}
|
|
175
|
+
*/
|
|
176
|
+
function build_exploded_tet_geometry(tet_mesh, points, shrink) {
|
|
177
|
+
const tet_count = tet_mesh.count;
|
|
178
|
+
const float_count = tet_count * 4 * 3 * 3; // 4 faces × 3 verts × xyz
|
|
179
|
+
const positions = new Float32Array(float_count);
|
|
180
|
+
const normals = new Float32Array(float_count);
|
|
181
|
+
const s = shrink;
|
|
182
|
+
const t = 1 - s;
|
|
183
|
+
|
|
184
|
+
let write = 0;
|
|
185
|
+
|
|
186
|
+
tet_mesh.forEach((tet) => {
|
|
187
|
+
const ai = tet_mesh.getVertexIndex(tet, 0);
|
|
188
|
+
const bi = tet_mesh.getVertexIndex(tet, 1);
|
|
189
|
+
const ci = tet_mesh.getVertexIndex(tet, 2);
|
|
190
|
+
const di = tet_mesh.getVertexIndex(tet, 3);
|
|
191
|
+
|
|
192
|
+
const ax = points[ai * 3], ay = points[ai * 3 + 1], az = points[ai * 3 + 2];
|
|
193
|
+
const bx = points[bi * 3], by = points[bi * 3 + 1], bz = points[bi * 3 + 2];
|
|
194
|
+
const cx = points[ci * 3], cy = points[ci * 3 + 1], cz = points[ci * 3 + 2];
|
|
195
|
+
const dx = points[di * 3], dy = points[di * 3 + 1], dz = points[di * 3 + 2];
|
|
196
|
+
|
|
197
|
+
const ccx = (ax + bx + cx + dx) * 0.25;
|
|
198
|
+
const ccy = (ay + by + cy + dy) * 0.25;
|
|
199
|
+
const ccz = (az + bz + cz + dz) * 0.25;
|
|
200
|
+
|
|
201
|
+
const A = [ax * s + ccx * t, ay * s + ccy * t, az * s + ccz * t];
|
|
202
|
+
const B = [bx * s + ccx * t, by * s + ccy * t, bz * s + ccz * t];
|
|
203
|
+
const C = [cx * s + ccx * t, cy * s + ccy * t, cz * s + ccz * t];
|
|
204
|
+
const D = [dx * s + ccx * t, dy * s + ccy * t, dz * s + ccz * t];
|
|
205
|
+
|
|
206
|
+
write = emit_face(positions, normals, write, B, C, D, A); // face opposite A
|
|
207
|
+
write = emit_face(positions, normals, write, A, D, C, B); // face opposite B
|
|
208
|
+
write = emit_face(positions, normals, write, A, B, D, C); // face opposite C
|
|
209
|
+
write = emit_face(positions, normals, write, A, C, B, D); // face opposite D
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const geometry = new BufferGeometry();
|
|
213
|
+
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
|
|
214
|
+
geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
|
|
215
|
+
return geometry;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// Tetrahedralization pipeline for a single input geometry
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Turn a three.js BufferGeometry (with its world matrix baked in) into a
|
|
224
|
+
* flat-shaded exploded-tet mesh plus measurement stats. Returns null if
|
|
225
|
+
* the input cannot be tetrahedralized.
|
|
226
|
+
*
|
|
227
|
+
* Stats included:
|
|
228
|
+
* - tet_count: number of live tets in the result
|
|
229
|
+
* - surface_volume: divergence-theorem volume of the input surface (the
|
|
230
|
+
* target we're trying to fill — caveat: only correct
|
|
231
|
+
* if the surface is properly closed and consistently
|
|
232
|
+
* wound. For meshes with holes / mixed winding the
|
|
233
|
+
* number is an approximation.)
|
|
234
|
+
* - tet_volume: sum of all tet volumes in the output
|
|
235
|
+
* - min_quality, avg_quality: radius-ratio quality (1 = regular tet,
|
|
236
|
+
* 0 = degenerate)
|
|
237
|
+
* - sliver_count: tets below SLIVER_QUALITY_THRESHOLD
|
|
238
|
+
*
|
|
239
|
+
* @param {BufferGeometry} input_geometry
|
|
240
|
+
* @returns {{
|
|
241
|
+
* geometry: BufferGeometry,
|
|
242
|
+
* tet_count: number,
|
|
243
|
+
* surface_volume: number,
|
|
244
|
+
* tet_volume: number,
|
|
245
|
+
* min_quality: number,
|
|
246
|
+
* avg_quality: number,
|
|
247
|
+
* sliver_count: number,
|
|
248
|
+
* } | null}
|
|
249
|
+
*/
|
|
250
|
+
function tetrahedralize_geometry(input_geometry) {
|
|
251
|
+
const positions_attr = input_geometry.getAttribute('position');
|
|
252
|
+
if (!positions_attr || positions_attr.count < 3) return null;
|
|
253
|
+
|
|
254
|
+
// Pull out positions + indices, fabricating trivial indices if the input
|
|
255
|
+
// is non-indexed (every 3 vertices = 1 triangle).
|
|
256
|
+
const positions = Array.from(positions_attr.array);
|
|
257
|
+
let indices;
|
|
258
|
+
if (input_geometry.index) {
|
|
259
|
+
indices = Array.from(input_geometry.index.array);
|
|
260
|
+
} else {
|
|
261
|
+
const n = positions_attr.count;
|
|
262
|
+
indices = new Array(n);
|
|
263
|
+
for (let i = 0; i < n; i++) indices[i] = i;
|
|
264
|
+
}
|
|
265
|
+
if (indices.length < 3) return null;
|
|
266
|
+
|
|
267
|
+
// GLTF often duplicates positions at smoothing/UV splits — that's fine,
|
|
268
|
+
// compute_tetrahedral_mesh_from_surface merges coincident vertices via
|
|
269
|
+
// bt_merge_verts_by_distance internally before tetrahedralizing.
|
|
270
|
+
const surface = new BinaryTopology();
|
|
271
|
+
bt_mesh_from_indexed_geometry(surface, indices, positions);
|
|
272
|
+
|
|
273
|
+
const surface_volume = Math.abs(triangle_mesh_compute_signed_volume(positions, indices));
|
|
274
|
+
|
|
275
|
+
const tet_mesh = new TetrahedralMesh();
|
|
276
|
+
let tet_positions;
|
|
277
|
+
try {
|
|
278
|
+
tet_positions = compute_tetrahedral_mesh_from_surface(tet_mesh, surface);
|
|
279
|
+
} catch (e) {
|
|
280
|
+
console.warn('Tetrahedralization failed for one geometry:', e);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (tet_mesh.count === 0) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const stats_before = measure_tet_stats(tet_mesh, tet_positions);
|
|
289
|
+
|
|
290
|
+
// Sliver-removal driver: try Laplacian smoothing + 2-3 / 3-2 flips on
|
|
291
|
+
// every tet below IMPROVE_TARGET_QUALITY. Off by toggling the constant
|
|
292
|
+
// at top of file. Stats are captured before+after so the per-mesh
|
|
293
|
+
// console line shows whether the driver actually moved the needle.
|
|
294
|
+
let stats_after = stats_before;
|
|
295
|
+
let driver_stats = null;
|
|
296
|
+
let driver_ms = 0;
|
|
297
|
+
if (ENABLE_IMPROVE_QUALITY) {
|
|
298
|
+
const t = performance.now();
|
|
299
|
+
driver_stats = tetrahedral_mesh_improve_quality(tet_mesh, tet_positions, {
|
|
300
|
+
target_quality: IMPROVE_TARGET_QUALITY,
|
|
301
|
+
max_passes: IMPROVE_MAX_PASSES,
|
|
302
|
+
});
|
|
303
|
+
driver_ms = performance.now() - t;
|
|
304
|
+
stats_after = measure_tet_stats(tet_mesh, tet_positions);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const out_geom = build_exploded_tet_geometry(tet_mesh, tet_positions, EXPLODE_FACTOR);
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
geometry: out_geom,
|
|
311
|
+
tet_count: tet_mesh.count,
|
|
312
|
+
surface_volume,
|
|
313
|
+
tet_volume: stats_after.tet_volume,
|
|
314
|
+
min_quality: stats_after.min_quality,
|
|
315
|
+
avg_quality: stats_after.avg_quality,
|
|
316
|
+
sliver_count: stats_after.sliver_count,
|
|
317
|
+
stats_before,
|
|
318
|
+
stats_after,
|
|
319
|
+
driver_stats,
|
|
320
|
+
driver_ms,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* One pass over a tet mesh: total signed volume, min and average
|
|
326
|
+
* radius-ratio quality, count of tets below the sliver threshold.
|
|
327
|
+
*
|
|
328
|
+
* @param {TetrahedralMesh} tet_mesh
|
|
329
|
+
* @param {Float32Array|number[]} tet_positions
|
|
330
|
+
* @returns {{tet_volume: number, min_quality: number, avg_quality: number, sliver_count: number}}
|
|
331
|
+
*/
|
|
332
|
+
function measure_tet_stats(tet_mesh, tet_positions) {
|
|
333
|
+
let tet_volume = 0;
|
|
334
|
+
let min_quality = 1;
|
|
335
|
+
let q_sum = 0;
|
|
336
|
+
let sliver_count = 0;
|
|
337
|
+
tet_mesh.forEach((tet, m) => {
|
|
338
|
+
tet_volume += compute_tetrahedron_volume(m, tet_positions, tet);
|
|
339
|
+
const q = compute_tetrahedron_quality(m, tet_positions, tet);
|
|
340
|
+
if (q < min_quality) min_quality = q;
|
|
341
|
+
q_sum += q;
|
|
342
|
+
if (q < SLIVER_QUALITY_THRESHOLD) sliver_count++;
|
|
343
|
+
});
|
|
344
|
+
const avg_quality = tet_mesh.count > 0 ? q_sum / tet_mesh.count : 0;
|
|
345
|
+
return { tet_volume, min_quality, avg_quality, sliver_count };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ---------------------------------------------------------------------------
|
|
349
|
+
// Scene management
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
|
|
352
|
+
const scene = new Scene();
|
|
353
|
+
scene.background = null; // let CSS show through
|
|
354
|
+
|
|
355
|
+
const camera = new PerspectiveCamera(45, 1, 0.01, 10000);
|
|
356
|
+
camera.position.set(4, 4, 6);
|
|
357
|
+
|
|
358
|
+
const renderer = new WebGLRenderer({ antialias: true });
|
|
359
|
+
renderer.setPixelRatio(window.devicePixelRatio);
|
|
360
|
+
renderer.setClearColor(BACKGROUND_COLOR, 1);
|
|
361
|
+
|
|
362
|
+
document.body.style.margin = '0';
|
|
363
|
+
document.body.style.overflow = 'hidden';
|
|
364
|
+
document.body.style.background = `#${BACKGROUND_COLOR.toString(16).padStart(6, '0')}`;
|
|
365
|
+
document.body.appendChild(renderer.domElement);
|
|
366
|
+
|
|
367
|
+
scene.add(new AmbientLight(0xffffff, 0.45));
|
|
368
|
+
const key_light = new DirectionalLight(0xffffff, 0.9);
|
|
369
|
+
key_light.position.set(3, 5, 4);
|
|
370
|
+
scene.add(key_light);
|
|
371
|
+
const fill_light = new DirectionalLight(0xa0b8ff, 0.35);
|
|
372
|
+
fill_light.position.set(-4, -2, -3);
|
|
373
|
+
scene.add(fill_light);
|
|
374
|
+
|
|
375
|
+
const controls = new OrbitControls(camera, renderer.domElement);
|
|
376
|
+
controls.enableDamping = true;
|
|
377
|
+
controls.dampingFactor = 0.08;
|
|
378
|
+
|
|
379
|
+
const loaded_group = new Group();
|
|
380
|
+
scene.add(loaded_group);
|
|
381
|
+
|
|
382
|
+
function clear_loaded() {
|
|
383
|
+
while (loaded_group.children.length > 0) {
|
|
384
|
+
const child = loaded_group.children.pop();
|
|
385
|
+
if (child.geometry) child.geometry.dispose();
|
|
386
|
+
if (child.material) child.material.dispose();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function fit_camera_to(group) {
|
|
391
|
+
const min = new ThreeVector3(Infinity, Infinity, Infinity);
|
|
392
|
+
const max = new ThreeVector3(-Infinity, -Infinity, -Infinity);
|
|
393
|
+
const tmp = new ThreeVector3();
|
|
394
|
+
|
|
395
|
+
group.traverse((obj) => {
|
|
396
|
+
if (!obj.geometry) return;
|
|
397
|
+
const attr = obj.geometry.getAttribute('position');
|
|
398
|
+
if (!attr) return;
|
|
399
|
+
for (let i = 0; i < attr.count; i++) {
|
|
400
|
+
tmp.set(attr.getX(i), attr.getY(i), attr.getZ(i));
|
|
401
|
+
obj.localToWorld(tmp);
|
|
402
|
+
min.min(tmp);
|
|
403
|
+
max.max(tmp);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
if (!isFinite(min.x)) return;
|
|
408
|
+
|
|
409
|
+
const center = min.clone().add(max).multiplyScalar(0.5);
|
|
410
|
+
const size = max.clone().sub(min);
|
|
411
|
+
const radius = size.length() * 0.5;
|
|
412
|
+
const dist = (radius / Math.sin((camera.fov * Math.PI / 180) / 2)) * CAMERA_FIT_PADDING;
|
|
413
|
+
|
|
414
|
+
const dir = new ThreeVector3(1, 0.6, 1.2).normalize();
|
|
415
|
+
camera.position.copy(center).add(dir.multiplyScalar(dist));
|
|
416
|
+
camera.near = Math.max(0.001, dist * 0.001);
|
|
417
|
+
camera.far = dist * 100;
|
|
418
|
+
camera.updateProjectionMatrix();
|
|
419
|
+
|
|
420
|
+
controls.target.copy(center);
|
|
421
|
+
controls.update();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ---------------------------------------------------------------------------
|
|
425
|
+
// Drag & drop UI
|
|
426
|
+
// ---------------------------------------------------------------------------
|
|
427
|
+
|
|
428
|
+
const overlay = document.createElement('div');
|
|
429
|
+
Object.assign(overlay.style, {
|
|
430
|
+
position: 'fixed',
|
|
431
|
+
inset: '0',
|
|
432
|
+
display: 'flex',
|
|
433
|
+
flexDirection: 'column',
|
|
434
|
+
alignItems: 'center',
|
|
435
|
+
justifyContent: 'center',
|
|
436
|
+
color: 'rgba(255,255,255,0.55)',
|
|
437
|
+
fontFamily: 'system-ui, sans-serif',
|
|
438
|
+
fontSize: '20px',
|
|
439
|
+
pointerEvents: 'none',
|
|
440
|
+
transition: 'opacity 0.2s ease',
|
|
441
|
+
textAlign: 'center',
|
|
442
|
+
padding: '24px',
|
|
443
|
+
});
|
|
444
|
+
overlay.innerHTML = `
|
|
445
|
+
<div style="font-size:42px;margin-bottom:12px;">⬇</div>
|
|
446
|
+
<div>Drop a <b>.gltf</b> or <b>.glb</b> file anywhere</div>
|
|
447
|
+
<div style="font-size:14px;margin-top:8px;opacity:0.7;">
|
|
448
|
+
Each mesh inside will be tetrahedralized and shown in a distinct colour.
|
|
449
|
+
</div>
|
|
450
|
+
`;
|
|
451
|
+
document.body.appendChild(overlay);
|
|
452
|
+
|
|
453
|
+
const status_bar = document.createElement('div');
|
|
454
|
+
Object.assign(status_bar.style, {
|
|
455
|
+
position: 'fixed',
|
|
456
|
+
left: '12px',
|
|
457
|
+
bottom: '12px',
|
|
458
|
+
color: 'rgba(255,255,255,0.85)',
|
|
459
|
+
fontFamily: 'monospace',
|
|
460
|
+
fontSize: '13px',
|
|
461
|
+
background: 'rgba(0,0,0,0.4)',
|
|
462
|
+
padding: '6px 10px',
|
|
463
|
+
borderRadius: '4px',
|
|
464
|
+
pointerEvents: 'none',
|
|
465
|
+
whiteSpace: 'pre',
|
|
466
|
+
});
|
|
467
|
+
document.body.appendChild(status_bar);
|
|
468
|
+
|
|
469
|
+
function set_status(text) {
|
|
470
|
+
status_bar.textContent = text;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
set_status('Ready. Drop a .gltf or .glb file.');
|
|
474
|
+
|
|
475
|
+
['dragenter', 'dragover'].forEach((ev) => {
|
|
476
|
+
window.addEventListener(ev, (e) => {
|
|
477
|
+
e.preventDefault();
|
|
478
|
+
overlay.style.background = 'rgba(60,100,140,0.25)';
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
['dragleave', 'drop'].forEach((ev) => {
|
|
482
|
+
window.addEventListener(ev, (e) => {
|
|
483
|
+
e.preventDefault();
|
|
484
|
+
overlay.style.background = '';
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
window.addEventListener('drop', (e) => {
|
|
489
|
+
const file = e.dataTransfer?.files?.[0];
|
|
490
|
+
if (!file) return;
|
|
491
|
+
handle_dropped_file(file);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
const gltf_loader = new GLTFLoader();
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @param {File} file
|
|
498
|
+
*/
|
|
499
|
+
function handle_dropped_file(file) {
|
|
500
|
+
set_status(`Reading ${file.name}…`);
|
|
501
|
+
|
|
502
|
+
const reader = new FileReader();
|
|
503
|
+
reader.onload = () => {
|
|
504
|
+
const buffer = reader.result;
|
|
505
|
+
const is_glb = file.name.toLowerCase().endsWith('.glb');
|
|
506
|
+
|
|
507
|
+
// GLTFLoader.parse accepts an ArrayBuffer (for .glb) or a JSON string
|
|
508
|
+
// (for .gltf). For .gltf, the result.scenes won't include external
|
|
509
|
+
// .bin buffers — that's a known limitation of single-file drag-drop.
|
|
510
|
+
try {
|
|
511
|
+
let data;
|
|
512
|
+
if (is_glb) {
|
|
513
|
+
data = buffer;
|
|
514
|
+
} else {
|
|
515
|
+
data = new TextDecoder().decode(buffer);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
gltf_loader.parse(
|
|
519
|
+
data,
|
|
520
|
+
'',
|
|
521
|
+
(gltf) => process_gltf(gltf, file.name),
|
|
522
|
+
(err) => {
|
|
523
|
+
console.error(err);
|
|
524
|
+
set_status(`Failed to parse ${file.name}: ${err?.message ?? err}`);
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
} catch (err) {
|
|
528
|
+
console.error(err);
|
|
529
|
+
set_status(`Failed to read ${file.name}: ${err.message}`);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
reader.onerror = () => set_status(`Failed to read ${file.name}`);
|
|
533
|
+
reader.readAsArrayBuffer(file);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* @param {{scene: import("three").Group}} gltf
|
|
538
|
+
* @param {string} file_name
|
|
539
|
+
*/
|
|
540
|
+
function process_gltf(gltf, file_name) {
|
|
541
|
+
clear_loaded();
|
|
542
|
+
overlay.style.opacity = '0';
|
|
543
|
+
|
|
544
|
+
gltf.scene.updateWorldMatrix(true, true);
|
|
545
|
+
|
|
546
|
+
/** @type {Array<{name: string, geometry: BufferGeometry}>} */
|
|
547
|
+
const inputs = [];
|
|
548
|
+
|
|
549
|
+
gltf.scene.traverse((obj) => {
|
|
550
|
+
if (!obj.isMesh || !obj.geometry) return;
|
|
551
|
+
// Bake world transform so every geometry lives in the same coordinate frame.
|
|
552
|
+
const baked = obj.geometry.clone();
|
|
553
|
+
baked.applyMatrix4(obj.matrixWorld);
|
|
554
|
+
inputs.push({ name: obj.name || `mesh_${inputs.length}`, geometry: baked });
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
if (inputs.length === 0) {
|
|
558
|
+
set_status(`${file_name}: no meshes found.`);
|
|
559
|
+
overlay.style.opacity = '1';
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
set_status(`${file_name}: tetrahedralizing ${inputs.length} mesh(es)…`);
|
|
564
|
+
|
|
565
|
+
let total_tets = 0;
|
|
566
|
+
let total_slivers = 0;
|
|
567
|
+
let total_surface_vol = 0;
|
|
568
|
+
let total_tet_vol = 0;
|
|
569
|
+
let global_min_quality = 1;
|
|
570
|
+
let q_sum_weighted = 0; // sum of avg_quality × tet_count, for a proper aggregate average
|
|
571
|
+
let succeeded = 0;
|
|
572
|
+
const t0 = performance.now();
|
|
573
|
+
|
|
574
|
+
inputs.forEach((input, i) => {
|
|
575
|
+
const color = color_for_index(i);
|
|
576
|
+
|
|
577
|
+
let result;
|
|
578
|
+
try {
|
|
579
|
+
result = tetrahedralize_geometry(input.geometry);
|
|
580
|
+
} catch (e) {
|
|
581
|
+
console.warn(`Tetrahedralization threw for "${input.name}":`, e);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (result === null) {
|
|
585
|
+
console.warn(`Tetrahedralization yielded no tets for "${input.name}".`);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const material = new MeshStandardMaterial({
|
|
590
|
+
color,
|
|
591
|
+
flatShading: true,
|
|
592
|
+
roughness: 0.6,
|
|
593
|
+
metalness: 0.05,
|
|
594
|
+
});
|
|
595
|
+
const mesh = new Mesh(result.geometry, material);
|
|
596
|
+
mesh.name = input.name;
|
|
597
|
+
loaded_group.add(mesh);
|
|
598
|
+
|
|
599
|
+
succeeded += 1;
|
|
600
|
+
total_tets += result.tet_count;
|
|
601
|
+
total_slivers += result.sliver_count;
|
|
602
|
+
total_surface_vol += result.surface_volume;
|
|
603
|
+
total_tet_vol += result.tet_volume;
|
|
604
|
+
q_sum_weighted += result.avg_quality * result.tet_count;
|
|
605
|
+
if (result.min_quality < global_min_quality) global_min_quality = result.min_quality;
|
|
606
|
+
|
|
607
|
+
// Per-mesh details to the console. The line shows BEFORE → AFTER
|
|
608
|
+
// the improve-quality driver so we can immediately see whether it
|
|
609
|
+
// moved the needle on this specific mesh.
|
|
610
|
+
const gap_pct = result.surface_volume > 0
|
|
611
|
+
? ((result.tet_volume - result.surface_volume) / result.surface_volume * 100).toFixed(2) + '%'
|
|
612
|
+
: 'n/a';
|
|
613
|
+
const before = result.stats_before;
|
|
614
|
+
const after = result.stats_after;
|
|
615
|
+
const driver_summary = result.driver_stats
|
|
616
|
+
? ` (${result.driver_ms.toFixed(0)}ms; smooth=${result.driver_stats.smoothings_committed}, flip23=${result.driver_stats.flips_23_committed}, flip32=${result.driver_stats.flips_32_committed})`
|
|
617
|
+
: '';
|
|
618
|
+
// eslint-disable-next-line no-console
|
|
619
|
+
console.log(
|
|
620
|
+
`[${input.name}] tets=${result.tet_count} ` +
|
|
621
|
+
`surf_vol=${result.surface_volume.toFixed(4)} tet_vol=${result.tet_volume.toFixed(4)} gap=${gap_pct}\n` +
|
|
622
|
+
` min_q: ${before.min_quality.toFixed(3)} → ${after.min_quality.toFixed(3)} ` +
|
|
623
|
+
`avg_q: ${before.avg_quality.toFixed(3)} → ${after.avg_quality.toFixed(3)} ` +
|
|
624
|
+
`slivers: ${before.sliver_count} → ${after.sliver_count}${driver_summary}`
|
|
625
|
+
);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
const ms = (performance.now() - t0).toFixed(0);
|
|
629
|
+
|
|
630
|
+
if (succeeded === 0) {
|
|
631
|
+
set_status(`${file_name}: all ${inputs.length} mesh(es) failed to tetrahedralize. See console.`);
|
|
632
|
+
overlay.style.opacity = '1';
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
fit_camera_to(loaded_group);
|
|
637
|
+
|
|
638
|
+
const aggregate_avg_q = total_tets > 0 ? q_sum_weighted / total_tets : 0;
|
|
639
|
+
const aggregate_gap = total_surface_vol > 0
|
|
640
|
+
? ((total_tet_vol - total_surface_vol) / total_surface_vol * 100).toFixed(2) + '%'
|
|
641
|
+
: 'n/a';
|
|
642
|
+
const sliver_pct = total_tets > 0
|
|
643
|
+
? (total_slivers / total_tets * 100).toFixed(1) + '%'
|
|
644
|
+
: '0%';
|
|
645
|
+
|
|
646
|
+
set_status(
|
|
647
|
+
`${file_name}\n` +
|
|
648
|
+
`meshes: ${succeeded}/${inputs.length} tets: ${total_tets.toLocaleString()} time: ${ms} ms\n` +
|
|
649
|
+
`vol: surf=${total_surface_vol.toFixed(4)} tet=${total_tet_vol.toFixed(4)} gap=${aggregate_gap}\n` +
|
|
650
|
+
`quality: min=${global_min_quality.toFixed(3)} avg=${aggregate_avg_q.toFixed(3)} slivers: ${total_slivers} (${sliver_pct})\n` +
|
|
651
|
+
`(drop another file to replace; per-mesh details in console)`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// ---------------------------------------------------------------------------
|
|
656
|
+
// Render loop & resize
|
|
657
|
+
// ---------------------------------------------------------------------------
|
|
658
|
+
|
|
659
|
+
function on_resize() {
|
|
660
|
+
const w = window.innerWidth;
|
|
661
|
+
const h = window.innerHeight;
|
|
662
|
+
renderer.setSize(w, h, false);
|
|
663
|
+
camera.aspect = w / h;
|
|
664
|
+
camera.updateProjectionMatrix();
|
|
665
|
+
}
|
|
666
|
+
window.addEventListener('resize', on_resize);
|
|
667
|
+
on_resize();
|
|
668
|
+
|
|
669
|
+
(function animate() {
|
|
670
|
+
requestAnimationFrame(animate);
|
|
671
|
+
controls.update();
|
|
672
|
+
renderer.render(scene, camera);
|
|
673
|
+
})();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Carve a Delaunay tetrahedralization so only the tets inside the input
|
|
3
|
+
* surface remain. Operates on a TetrahedralMesh whose vertex IDs are aligned
|
|
4
|
+
* with the surface's vertex IDs — both index into the same flat positions
|
|
5
|
+
* array used by `compute_delaunay_tetrahedral_mesh`.
|
|
6
|
+
*
|
|
7
|
+
* Algorithm: build a BVH over the surface triangles, then for every tet,
|
|
8
|
+
* classify its centroid as inside or outside via parity ray-casting against
|
|
9
|
+
* the BVH. Exterior tets are disconnected and deleted.
|
|
10
|
+
*
|
|
11
|
+
* Pure ray-cast classification is intentional. A flood-fill optimisation over
|
|
12
|
+
* tet adjacency would be cheaper but is unsafe when the Delaunay's diagonals
|
|
13
|
+
* differ from the surface's (always the case for coarse meshes like a cube,
|
|
14
|
+
* common for finer meshes): leaked surface triangles let the fill cross from
|
|
15
|
+
* interior to exterior unchecked, deleting tets that should be kept.
|
|
16
|
+
*
|
|
17
|
+
* @param {TetrahedralMesh} tet_mesh mutated in place
|
|
18
|
+
* @param {ArrayLike<number>|Float32Array} positions same flat (x,y,z) array used in the Delaunay pass
|
|
19
|
+
* @param {BinaryTopology} surface watertight surface mesh defining inside/outside
|
|
20
|
+
* @returns {{deleted: number, kept: number}}
|
|
21
|
+
*/
|
|
22
|
+
export function tetrahedral_mesh_carve_outside_surface(tet_mesh: TetrahedralMesh, positions: ArrayLike<number> | Float32Array, surface: BinaryTopology): {
|
|
23
|
+
deleted: number;
|
|
24
|
+
kept: number;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=tetrahedral_mesh_carve_outside_surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tetrahedral_mesh_carve_outside_surface.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js"],"names":[],"mappings":"AAoJA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,6FAJW,UAAU,MAAM,CAAC,GAAC,YAAY;aAElB,MAAM;UAAQ,MAAM;EAsD1C"}
|