@woosh/meep-engine 2.139.0 → 2.141.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 +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts +3 -3
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_aabb.js +4 -4
- package/src/{engine/physics/broadphase/aabb_transform_oriented.d.ts → core/geom/3d/aabb/aabb3_transform_oriented.d.ts} +2 -2
- package/src/core/geom/3d/aabb/aabb3_transform_oriented.d.ts.map +1 -0
- package/src/{engine/physics/broadphase/aabb_transform_oriented.js → core/geom/3d/aabb/aabb3_transform_oriented.js} +1 -1
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts +21 -0
- package/src/core/geom/3d/quaternion/quat3_multiply.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_multiply.js +25 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts +54 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -0
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts +24 -2
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/AbstractShape3D.js +24 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +148 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.js +451 -0
- package/src/core/geom/3d/shape/MeshShape3D.d.ts +210 -0
- package/src/core/geom/3d/shape/MeshShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/MeshShape3D.js +593 -0
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +46 -2
- package/src/core/geom/3d/shape/Triangle3D.d.ts +95 -0
- package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/Triangle3D.js +318 -0
- package/src/core/geom/3d/shape/UnionShape3D.js +13 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts +30 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.d.ts.map +1 -0
- package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +64 -0
- package/src/core/geom/3d/tetrahedra/prototype_tetrahedrize_mesh.js +9 -11
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts +28 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +40 -18
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts +9 -5
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +38 -10
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts +14 -5
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +47 -5
- package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.d.ts +19 -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 +75 -13
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts +2 -2
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +1 -1
- package/src/core/geom/vec3/v3_dot_array_array.d.ts +3 -3
- package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_dot_array_array.js +2 -2
- package/src/core/geom/vec3/v3_negate_array.d.ts +3 -3
- package/src/core/geom/vec3/v3_negate_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_negate_array.js +2 -2
- package/src/core/geom/vec3/v3_quat3_apply.d.ts +29 -0
- package/src/core/geom/vec3/v3_quat3_apply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_quat3_apply.js +39 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +30 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_quat3_apply_inverse.js +41 -0
- package/src/core/geom/vec3/v3_triple_cross_product.d.ts +32 -0
- package/src/core/geom/vec3/v3_triple_cross_product.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_triple_cross_product.js +45 -0
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +16 -3
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerController.js +211 -211
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +72 -8
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +37 -5
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +101 -3
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1789 -1416
- package/src/engine/control/first-person/TODO.md +173 -127
- package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Slide.js +9 -1
- package/src/engine/control/first-person/prototype_first_person_controller.js +88 -2
- package/src/engine/control/first-person/test/buildTestPlayer.d.ts.map +1 -1
- package/src/engine/control/first-person/test/buildTestPlayer.js +9 -1
- package/src/engine/graphics/geometry/CapsuleGeometry.d.ts +42 -0
- package/src/engine/graphics/geometry/CapsuleGeometry.d.ts.map +1 -0
- package/src/engine/graphics/geometry/CapsuleGeometry.js +171 -0
- package/src/engine/physics/BULLET_REVIEW.md +945 -0
- package/src/engine/physics/CANNON_REVIEW.md +1300 -0
- package/src/engine/physics/JOLT_REVIEW.md +913 -0
- package/src/engine/physics/PLAN.md +578 -236
- package/src/engine/physics/RAPIER_REVIEW.md +934 -0
- package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -0
- package/src/engine/physics/REVIEW_002.md +151 -0
- package/src/engine/physics/broadphase/compute_fat_world_aabb.js +2 -2
- package/src/engine/physics/constraint/DofMode.d.ts +28 -0
- package/src/engine/physics/constraint/DofMode.d.ts.map +1 -0
- package/src/engine/physics/constraint/DofMode.js +35 -0
- package/src/engine/physics/constraint/solve_constraints.d.ts +16 -0
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -0
- package/src/engine/physics/constraint/solve_constraints.js +436 -0
- package/src/engine/physics/contact/ManifoldStore.d.ts +83 -10
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
- package/src/engine/physics/contact/ManifoldStore.js +608 -499
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts +2 -2
- package/src/engine/physics/ecs/ColliderObserverSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/Joint.d.ts +179 -0
- package/src/engine/physics/ecs/Joint.d.ts.map +1 -0
- package/src/engine/physics/ecs/Joint.js +234 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +180 -20
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +1423 -1159
- package/src/engine/physics/fluid/FluidField.d.ts +14 -10
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +14 -10
- package/src/engine/physics/fluid/FluidSimulator.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +17 -10
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +18 -11
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +13 -10
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +18 -13
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +4 -3
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +15 -11
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +30 -6
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +44 -18
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +6 -6
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -1
- package/src/engine/physics/gjk/expanding_polytope_algorithm.js +68 -22
- package/src/engine/physics/gjk/gjk.d.ts +28 -2
- package/src/engine/physics/gjk/gjk.d.ts.map +1 -1
- package/src/engine/physics/gjk/gjk.js +421 -378
- package/src/engine/physics/gjk/minkowski_support.d.ts +37 -0
- package/src/engine/physics/gjk/minkowski_support.d.ts.map +1 -0
- package/src/engine/physics/gjk/minkowski_support.js +75 -0
- package/src/engine/physics/gjk/mpr.d.ts +56 -0
- package/src/engine/physics/gjk/mpr.d.ts.map +1 -0
- package/src/engine/physics/gjk/mpr.js +344 -0
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +20 -5
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +36 -38
- package/src/engine/physics/integration/integrate_position.d.ts +25 -7
- package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_position.js +43 -12
- package/src/engine/physics/integration/integrate_velocity.d.ts +30 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +82 -1
- package/src/engine/physics/island/IslandBuilder.d.ts +4 -1
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
- package/src/engine/physics/island/IslandBuilder.js +33 -16
- package/src/engine/physics/narrowphase/PosedShape.d.ts +0 -8
- package/src/engine/physics/narrowphase/PosedShape.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/PosedShape.js +28 -30
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +140 -18
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts +30 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/box_triangle_contact.js +811 -0
- package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/capsule_contacts.js +10 -56
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts +71 -0
- package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/capsule_triangle_contact.js +375 -0
- package/src/engine/physics/narrowphase/compute_penetration.d.ts +91 -0
- package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/compute_penetration.js +396 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts +35 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.js +80 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts +31 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +42 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +204 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +42 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +94 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts +37 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts +41 -2
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +1497 -382
- package/src/engine/physics/narrowphase/sphere_box_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/sphere_box_contact.js +16 -23
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts +48 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/sphere_triangle_contact.js +143 -0
- package/src/engine/physics/queries/overlap_shape.d.ts +51 -0
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -0
- package/src/engine/physics/queries/overlap_shape.js +183 -0
- package/src/engine/physics/queries/shape_cast.d.ts +56 -0
- package/src/engine/physics/queries/shape_cast.d.ts.map +1 -0
- package/src/engine/physics/queries/shape_cast.js +387 -0
- package/src/engine/physics/solver/solve_contacts.d.ts +146 -32
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +809 -223
- package/src/engine/physics/broadphase/aabb_transform_oriented.d.ts.map +0 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts +0 -20
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.d.ts.map +0 -1
- package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_unmasked_legacy.js +0 -83
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buffer-backed flyweight triangle shape.
|
|
3
|
+
*
|
|
4
|
+
* Vertex data is NOT stored on the instance — instead the triangle binds
|
|
5
|
+
* to a region of an external Float64 buffer via {@link bind}, reading
|
|
6
|
+
* 9 consecutive floats (vA.xyz, vB.xyz, vC.xyz) at the bound offset.
|
|
7
|
+
*
|
|
8
|
+
* Pattern: the narrowphase keeps one persistent `Triangle3D` per side of
|
|
9
|
+
* a contact pair and rebinds its offset while iterating decomposed
|
|
10
|
+
* triangles from a non-convex shape's enumerator. Zero allocations per
|
|
11
|
+
* iteration step — the cost of "another triangle" is a single integer
|
|
12
|
+
* offset change.
|
|
13
|
+
*
|
|
14
|
+
* The shape is convex (a triangle is the canonical 2-simplex in 3D, and
|
|
15
|
+
* GJK handles 2-simplices natively). It's degenerate in the sense that
|
|
16
|
+
* `volume = 0` and `contains_point` is always false — a triangle is a
|
|
17
|
+
* 2D surface in 3D space, no interior.
|
|
18
|
+
*
|
|
19
|
+
* @author Alex Goldring
|
|
20
|
+
* @copyright Company Named Limited (c) 2026
|
|
21
|
+
*/
|
|
22
|
+
export class Triangle3D extends AbstractShape3D {
|
|
23
|
+
/**
|
|
24
|
+
* Convenience constructor for tests and one-off triangles.
|
|
25
|
+
* Allocates a private 9-float buffer; for hot paths use {@link bind}
|
|
26
|
+
* against a shared buffer instead.
|
|
27
|
+
*
|
|
28
|
+
* @param {number} ax
|
|
29
|
+
* @param {number} ay
|
|
30
|
+
* @param {number} az
|
|
31
|
+
* @param {number} bx
|
|
32
|
+
* @param {number} by
|
|
33
|
+
* @param {number} bz
|
|
34
|
+
* @param {number} cx
|
|
35
|
+
* @param {number} cy
|
|
36
|
+
* @param {number} cz
|
|
37
|
+
* @returns {Triangle3D}
|
|
38
|
+
*/
|
|
39
|
+
static from(ax: number, ay: number, az: number, bx: number, by: number, bz: number, cx: number, cy: number, cz: number): Triangle3D;
|
|
40
|
+
/**
|
|
41
|
+
* External buffer holding vertex data.
|
|
42
|
+
* @type {Float64Array | null}
|
|
43
|
+
*/
|
|
44
|
+
buffer: Float64Array | null;
|
|
45
|
+
/**
|
|
46
|
+
* Float-index of vA.x in {@link buffer}. The other 8 floats
|
|
47
|
+
* (vA.yz, vB.xyz, vC.xyz) follow consecutively.
|
|
48
|
+
* @type {number}
|
|
49
|
+
*/
|
|
50
|
+
offset: number;
|
|
51
|
+
/**
|
|
52
|
+
* Bind this triangle to a region of an external buffer. Reads 9
|
|
53
|
+
* consecutive floats starting at `offset`.
|
|
54
|
+
*
|
|
55
|
+
* @param {Float64Array} buffer
|
|
56
|
+
* @param {number} offset float-index of vA.x in the buffer
|
|
57
|
+
* @returns {Triangle3D} this (for chaining)
|
|
58
|
+
*/
|
|
59
|
+
bind(buffer: Float64Array, offset: number): Triangle3D;
|
|
60
|
+
support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
|
|
61
|
+
compute_bounding_box(result: any): void;
|
|
62
|
+
/**
|
|
63
|
+
* A triangle has zero interior volume.
|
|
64
|
+
*/
|
|
65
|
+
contains_point(_point: any): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Signed distance has a well-defined sign relative to the triangle's
|
|
68
|
+
* face plane: positive on the side that the face normal points to
|
|
69
|
+
* (normal = (B-A) × (C-A), CCW convention), negative on the other.
|
|
70
|
+
*
|
|
71
|
+
* Magnitude is the true point-to-triangle distance (handles vertex,
|
|
72
|
+
* edge, and face Voronoi regions correctly via
|
|
73
|
+
* {@link computeTriangleClosestPointToPointBarycentric}).
|
|
74
|
+
*/
|
|
75
|
+
signed_distance_at_point(point: any): number;
|
|
76
|
+
nearest_point_on_surface(result: any, reference: any): void;
|
|
77
|
+
/**
|
|
78
|
+
* Uniform random barycentric sample within the triangle.
|
|
79
|
+
* Triangles have no interior, so the sample lies on the surface.
|
|
80
|
+
*/
|
|
81
|
+
sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
|
|
82
|
+
/**
|
|
83
|
+
* @param {Triangle3D} other
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
equals(other: Triangle3D): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Fast type-check marker.
|
|
89
|
+
* @readonly
|
|
90
|
+
* @type {boolean}
|
|
91
|
+
*/
|
|
92
|
+
readonly isTriangle3D: boolean;
|
|
93
|
+
}
|
|
94
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
95
|
+
//# sourceMappingURL=Triangle3D.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Triangle3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/Triangle3D.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAmCI;;;;;;;;;;;;;;;OAeG;IACH,gBAXW,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,GACJ,UAAU,CAWtB;IAxDG;;;OAGG;IACH,QAFU,YAAY,GAAG,IAAI,CAEX;IAElB;;;;OAIG;IACH,QAFU,MAAM,CAED;IAGnB;;;;;;;OAOG;IACH,aAJW,YAAY,UACZ,MAAM,GACJ,UAAU,CAStB;IA6BD,qGAyBC;IAED,wCAeC;IAED;;OAEG;IACH,qCAEC;IAED;;;;;;;;OAQG;IACH,6CA4CC;IAED,4DAwBC;IAED;;;OAGG;IACH,kFAsBC;IAwBD;;;OAGG;IACH,cAHW,UAAU,GACR,OAAO,CAenB;IAgBL;;;;OAIG;IACH,uBAFU,OAAO,CAEgB;CAPhC;gCA1S+B,sBAAsB"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { assert } from "../../../assert.js";
|
|
2
|
+
import { computeHashFloat } from "../../../primitives/numbers/computeHashFloat.js";
|
|
3
|
+
import { v3_length } from "../../vec3/v3_length.js";
|
|
4
|
+
import { computeTriangleClosestPointToPointBarycentric } from "../triangle/computeTriangleClosestPointToPointBarycentric.js";
|
|
5
|
+
import { AbstractShape3D } from "./AbstractShape3D.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Buffer-backed flyweight triangle shape.
|
|
9
|
+
*
|
|
10
|
+
* Vertex data is NOT stored on the instance — instead the triangle binds
|
|
11
|
+
* to a region of an external Float64 buffer via {@link bind}, reading
|
|
12
|
+
* 9 consecutive floats (vA.xyz, vB.xyz, vC.xyz) at the bound offset.
|
|
13
|
+
*
|
|
14
|
+
* Pattern: the narrowphase keeps one persistent `Triangle3D` per side of
|
|
15
|
+
* a contact pair and rebinds its offset while iterating decomposed
|
|
16
|
+
* triangles from a non-convex shape's enumerator. Zero allocations per
|
|
17
|
+
* iteration step — the cost of "another triangle" is a single integer
|
|
18
|
+
* offset change.
|
|
19
|
+
*
|
|
20
|
+
* The shape is convex (a triangle is the canonical 2-simplex in 3D, and
|
|
21
|
+
* GJK handles 2-simplices natively). It's degenerate in the sense that
|
|
22
|
+
* `volume = 0` and `contains_point` is always false — a triangle is a
|
|
23
|
+
* 2D surface in 3D space, no interior.
|
|
24
|
+
*
|
|
25
|
+
* @author Alex Goldring
|
|
26
|
+
* @copyright Company Named Limited (c) 2026
|
|
27
|
+
*/
|
|
28
|
+
export class Triangle3D extends AbstractShape3D {
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* External buffer holding vertex data.
|
|
34
|
+
* @type {Float64Array | null}
|
|
35
|
+
*/
|
|
36
|
+
this.buffer = null;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Float-index of vA.x in {@link buffer}. The other 8 floats
|
|
40
|
+
* (vA.yz, vB.xyz, vC.xyz) follow consecutively.
|
|
41
|
+
* @type {number}
|
|
42
|
+
*/
|
|
43
|
+
this.offset = 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Bind this triangle to a region of an external buffer. Reads 9
|
|
48
|
+
* consecutive floats starting at `offset`.
|
|
49
|
+
*
|
|
50
|
+
* @param {Float64Array} buffer
|
|
51
|
+
* @param {number} offset float-index of vA.x in the buffer
|
|
52
|
+
* @returns {Triangle3D} this (for chaining)
|
|
53
|
+
*/
|
|
54
|
+
bind(buffer, offset) {
|
|
55
|
+
assert.isNonNegativeInteger(offset, "offset");
|
|
56
|
+
|
|
57
|
+
this.buffer = buffer;
|
|
58
|
+
this.offset = offset;
|
|
59
|
+
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Convenience constructor for tests and one-off triangles.
|
|
65
|
+
* Allocates a private 9-float buffer; for hot paths use {@link bind}
|
|
66
|
+
* against a shared buffer instead.
|
|
67
|
+
*
|
|
68
|
+
* @param {number} ax
|
|
69
|
+
* @param {number} ay
|
|
70
|
+
* @param {number} az
|
|
71
|
+
* @param {number} bx
|
|
72
|
+
* @param {number} by
|
|
73
|
+
* @param {number} bz
|
|
74
|
+
* @param {number} cx
|
|
75
|
+
* @param {number} cy
|
|
76
|
+
* @param {number} cz
|
|
77
|
+
* @returns {Triangle3D}
|
|
78
|
+
*/
|
|
79
|
+
static from(ax, ay, az, bx, by, bz, cx, cy, cz) {
|
|
80
|
+
const buf = new Float64Array(9);
|
|
81
|
+
buf[0] = ax; buf[1] = ay; buf[2] = az;
|
|
82
|
+
buf[3] = bx; buf[4] = by; buf[5] = bz;
|
|
83
|
+
buf[6] = cx; buf[7] = cy; buf[8] = cz;
|
|
84
|
+
|
|
85
|
+
const t = new Triangle3D();
|
|
86
|
+
t.bind(buf, 0);
|
|
87
|
+
return t;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
support(result, result_offset, direction_x, direction_y, direction_z) {
|
|
91
|
+
const b = this.buffer;
|
|
92
|
+
const o = this.offset;
|
|
93
|
+
|
|
94
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
95
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
96
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
97
|
+
|
|
98
|
+
const da = ax * direction_x + ay * direction_y + az * direction_z;
|
|
99
|
+
const db = bx * direction_x + by * direction_y + bz * direction_z;
|
|
100
|
+
const dc = cx * direction_x + cy * direction_y + cz * direction_z;
|
|
101
|
+
|
|
102
|
+
if (da >= db && da >= dc) {
|
|
103
|
+
result[result_offset ] = ax;
|
|
104
|
+
result[result_offset + 1] = ay;
|
|
105
|
+
result[result_offset + 2] = az;
|
|
106
|
+
} else if (db >= dc) {
|
|
107
|
+
result[result_offset ] = bx;
|
|
108
|
+
result[result_offset + 1] = by;
|
|
109
|
+
result[result_offset + 2] = bz;
|
|
110
|
+
} else {
|
|
111
|
+
result[result_offset ] = cx;
|
|
112
|
+
result[result_offset + 1] = cy;
|
|
113
|
+
result[result_offset + 2] = cz;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
compute_bounding_box(result) {
|
|
118
|
+
const b = this.buffer;
|
|
119
|
+
const o = this.offset;
|
|
120
|
+
|
|
121
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
122
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
123
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
124
|
+
|
|
125
|
+
result[0] = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx);
|
|
126
|
+
result[1] = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy);
|
|
127
|
+
result[2] = az < bz ? (az < cz ? az : cz) : (bz < cz ? bz : cz);
|
|
128
|
+
|
|
129
|
+
result[3] = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx);
|
|
130
|
+
result[4] = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
|
|
131
|
+
result[5] = az > bz ? (az > cz ? az : cz) : (bz > cz ? bz : cz);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* A triangle has zero interior volume.
|
|
136
|
+
*/
|
|
137
|
+
contains_point(_point) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Signed distance has a well-defined sign relative to the triangle's
|
|
143
|
+
* face plane: positive on the side that the face normal points to
|
|
144
|
+
* (normal = (B-A) × (C-A), CCW convention), negative on the other.
|
|
145
|
+
*
|
|
146
|
+
* Magnitude is the true point-to-triangle distance (handles vertex,
|
|
147
|
+
* edge, and face Voronoi regions correctly via
|
|
148
|
+
* {@link computeTriangleClosestPointToPointBarycentric}).
|
|
149
|
+
*/
|
|
150
|
+
signed_distance_at_point(point) {
|
|
151
|
+
const b = this.buffer;
|
|
152
|
+
const o = this.offset;
|
|
153
|
+
|
|
154
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
155
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
156
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
157
|
+
|
|
158
|
+
const px = point[0]; const py = point[1]; const pz = point[2];
|
|
159
|
+
|
|
160
|
+
computeTriangleClosestPointToPointBarycentric(
|
|
161
|
+
scratch_bary, 0,
|
|
162
|
+
px, py, pz,
|
|
163
|
+
ax, ay, az,
|
|
164
|
+
bx, by, bz,
|
|
165
|
+
cx, cy, cz
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// result format: [alpha_A, alpha_B]; alpha_C = 1 - alpha_A - alpha_B
|
|
169
|
+
const alpha_a = scratch_bary[0];
|
|
170
|
+
const alpha_b = scratch_bary[1];
|
|
171
|
+
const alpha_c = 1 - alpha_a - alpha_b;
|
|
172
|
+
|
|
173
|
+
const closest_x = alpha_a * ax + alpha_b * bx + alpha_c * cx;
|
|
174
|
+
const closest_y = alpha_a * ay + alpha_b * by + alpha_c * cy;
|
|
175
|
+
const closest_z = alpha_a * az + alpha_b * bz + alpha_c * cz;
|
|
176
|
+
|
|
177
|
+
const dx = px - closest_x;
|
|
178
|
+
const dy = py - closest_y;
|
|
179
|
+
const dz = pz - closest_z;
|
|
180
|
+
|
|
181
|
+
const distance = v3_length(dx, dy, dz);
|
|
182
|
+
|
|
183
|
+
// face normal = (B - A) × (C - A) — CCW convention
|
|
184
|
+
const e1x = bx - ax; const e1y = by - ay; const e1z = bz - az;
|
|
185
|
+
const e2x = cx - ax; const e2y = cy - ay; const e2z = cz - az;
|
|
186
|
+
|
|
187
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
188
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
189
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
190
|
+
|
|
191
|
+
const side = (px - ax) * nx + (py - ay) * ny + (pz - az) * nz;
|
|
192
|
+
|
|
193
|
+
return side >= 0 ? distance : -distance;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
nearest_point_on_surface(result, reference) {
|
|
197
|
+
const b = this.buffer;
|
|
198
|
+
const o = this.offset;
|
|
199
|
+
|
|
200
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
201
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
202
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
203
|
+
|
|
204
|
+
computeTriangleClosestPointToPointBarycentric(
|
|
205
|
+
scratch_bary, 0,
|
|
206
|
+
reference[0], reference[1], reference[2],
|
|
207
|
+
ax, ay, az,
|
|
208
|
+
bx, by, bz,
|
|
209
|
+
cx, cy, cz
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// result format: [alpha_A, alpha_B]; alpha_C = 1 - alpha_A - alpha_B
|
|
213
|
+
const alpha_a = scratch_bary[0];
|
|
214
|
+
const alpha_b = scratch_bary[1];
|
|
215
|
+
const alpha_c = 1 - alpha_a - alpha_b;
|
|
216
|
+
|
|
217
|
+
result[0] = alpha_a * ax + alpha_b * bx + alpha_c * cx;
|
|
218
|
+
result[1] = alpha_a * ay + alpha_b * by + alpha_c * cy;
|
|
219
|
+
result[2] = alpha_a * az + alpha_b * bz + alpha_c * cz;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Uniform random barycentric sample within the triangle.
|
|
224
|
+
* Triangles have no interior, so the sample lies on the surface.
|
|
225
|
+
*/
|
|
226
|
+
sample_random_point_in_volume(result, result_offset, random) {
|
|
227
|
+
let r1 = random();
|
|
228
|
+
let r2 = random();
|
|
229
|
+
|
|
230
|
+
// unit-square reflection trick for uniform-barycentric sampling
|
|
231
|
+
if (r1 + r2 > 1) {
|
|
232
|
+
r1 = 1 - r1;
|
|
233
|
+
r2 = 1 - r2;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const r0 = 1 - r1 - r2;
|
|
237
|
+
|
|
238
|
+
const b = this.buffer;
|
|
239
|
+
const o = this.offset;
|
|
240
|
+
|
|
241
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
242
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
243
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
244
|
+
|
|
245
|
+
result[result_offset ] = r0 * ax + r1 * bx + r2 * cx;
|
|
246
|
+
result[result_offset + 1] = r0 * ay + r1 * by + r2 * cy;
|
|
247
|
+
result[result_offset + 2] = r0 * az + r1 * bz + r2 * cz;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
get volume() {
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
get surface_area() {
|
|
255
|
+
const b = this.buffer;
|
|
256
|
+
const o = this.offset;
|
|
257
|
+
|
|
258
|
+
const ax = b[o ]; const ay = b[o + 1]; const az = b[o + 2];
|
|
259
|
+
const bx = b[o + 3]; const by = b[o + 4]; const bz = b[o + 5];
|
|
260
|
+
const cx = b[o + 6]; const cy = b[o + 7]; const cz = b[o + 8];
|
|
261
|
+
|
|
262
|
+
const e1x = bx - ax; const e1y = by - ay; const e1z = bz - az;
|
|
263
|
+
const e2x = cx - ax; const e2y = cy - ay; const e2z = cz - az;
|
|
264
|
+
|
|
265
|
+
const nx = e1y * e2z - e1z * e2y;
|
|
266
|
+
const ny = e1z * e2x - e1x * e2z;
|
|
267
|
+
const nz = e1x * e2y - e1y * e2x;
|
|
268
|
+
|
|
269
|
+
return 0.5 * v3_length(nx, ny, nz);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @param {Triangle3D} other
|
|
274
|
+
* @returns {boolean}
|
|
275
|
+
*/
|
|
276
|
+
equals(other) {
|
|
277
|
+
if (!super.equals(other)) return false;
|
|
278
|
+
|
|
279
|
+
const a = this.buffer;
|
|
280
|
+
const ao = this.offset;
|
|
281
|
+
const b = other.buffer;
|
|
282
|
+
const bo = other.offset;
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < 9; i++) {
|
|
285
|
+
if (a[ao + i] !== b[bo + i]) return false;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
hash() {
|
|
292
|
+
const b = this.buffer;
|
|
293
|
+
const o = this.offset;
|
|
294
|
+
|
|
295
|
+
let h = 0;
|
|
296
|
+
|
|
297
|
+
for (let i = 0; i < 9; i++) {
|
|
298
|
+
h = ((h << 5) - h + computeHashFloat(b[o + i])) | 0;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return h;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Fast type-check marker.
|
|
307
|
+
* @readonly
|
|
308
|
+
* @type {boolean}
|
|
309
|
+
*/
|
|
310
|
+
Triangle3D.prototype.isTriangle3D = true;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Scratch for barycentric output from {@link computeTriangleClosestPointToPointBarycentric}.
|
|
314
|
+
* Module-scoped because every triangle method that needs barycentric
|
|
315
|
+
* coords does it strictly inline — no nested calls that could re-enter.
|
|
316
|
+
* @type {Float64Array}
|
|
317
|
+
*/
|
|
318
|
+
const scratch_bary = new Float64Array(2);
|
|
@@ -352,3 +352,16 @@ export class UnionShape3D extends AbstractShape3D {
|
|
|
352
352
|
return hash;
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* The set-union of convex shapes is convex only in the trivial cases (one
|
|
358
|
+
* child, or fully overlapping children). The general case is non-convex,
|
|
359
|
+
* so the narrowphase must decompose the union into its children and run
|
|
360
|
+
* per-child GJK against the other body, then merge the resulting contact
|
|
361
|
+
* manifolds. Treating the union as a single convex blob via GJK on a
|
|
362
|
+
* combined support would conflate distinct children into a fake hull.
|
|
363
|
+
*
|
|
364
|
+
* @readonly
|
|
365
|
+
* @type {boolean}
|
|
366
|
+
*/
|
|
367
|
+
UnionShape3D.prototype.is_convex = false;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a {@link MeshShape3D} from a Three-style indexed triangle buffer.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline:
|
|
5
|
+
* 1. {@link bt_mesh_from_indexed_geometry} reconstructs a
|
|
6
|
+
* {@link BinaryTopology} (vertex / edge / loop / face cycles).
|
|
7
|
+
* 2. {@link compute_tetrahedral_mesh_from_surface} tetrahedralises the
|
|
8
|
+
* volume enclosed by the surface, carving away exterior tets.
|
|
9
|
+
* 3. The tet mesh is **compacted** — the carving pass leaves the free
|
|
10
|
+
* list populated with low-index slots, and downstream consumers
|
|
11
|
+
* (`tetrahedral_mesh_to_bvh` iterates by index, the shape's
|
|
12
|
+
* `recompute_cached` does the same) expect a hole-free range.
|
|
13
|
+
* Compaction relocates live tets so indices `[0, count)` are dense.
|
|
14
|
+
* 4. The flat positions + indices are kept verbatim on the shape for
|
|
15
|
+
* fast support-function and triangle-distance queries.
|
|
16
|
+
* 5. A {@link BVH} is built over the tet AABBs, used by
|
|
17
|
+
* {@link MeshShape3D#contains_point} for O(log N) point-in-mesh
|
|
18
|
+
* queries that correctly handle disconnected meshes (which the
|
|
19
|
+
* previous tet-walker did not).
|
|
20
|
+
*
|
|
21
|
+
* The caller's buffers are NOT cloned — they're attached to the shape
|
|
22
|
+
* directly. Don't mutate them after handing them in.
|
|
23
|
+
*
|
|
24
|
+
* @param {Float32Array} positions flat `(x, y, z)` per vertex
|
|
25
|
+
* @param {Uint32Array} indices three uint32 per triangle (CCW winding)
|
|
26
|
+
* @returns {MeshShape3D}
|
|
27
|
+
*/
|
|
28
|
+
export function shape_mesh_from_geometry(positions: Float32Array, indices: Uint32Array): MeshShape3D;
|
|
29
|
+
import { MeshShape3D } from "./MeshShape3D.js";
|
|
30
|
+
//# sourceMappingURL=shape_mesh_from_geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape_mesh_from_geometry.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/shape_mesh_from_geometry.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,oDAJW,YAAY,WACZ,WAAW,GACT,WAAW,CAgCvB;4BA3D2B,kBAAkB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { tetrahedral_mesh_to_bvh } from "../tetrahedra/bvh/tetrahedral_mesh_to_bvh.js";
|
|
2
|
+
import { compute_tetrahedral_mesh_from_surface } from "../tetrahedra/compute_tetrahedral_mesh_from_surface.js";
|
|
3
|
+
import { BinaryTopology } from "../topology/struct/binary/BinaryTopology.js";
|
|
4
|
+
import { bt_mesh_from_indexed_geometry } from "../topology/struct/binary/io/bt_mesh_from_indexed_geometry.js";
|
|
5
|
+
import { MeshShape3D } from "./MeshShape3D.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build a {@link MeshShape3D} from a Three-style indexed triangle buffer.
|
|
9
|
+
*
|
|
10
|
+
* Pipeline:
|
|
11
|
+
* 1. {@link bt_mesh_from_indexed_geometry} reconstructs a
|
|
12
|
+
* {@link BinaryTopology} (vertex / edge / loop / face cycles).
|
|
13
|
+
* 2. {@link compute_tetrahedral_mesh_from_surface} tetrahedralises the
|
|
14
|
+
* volume enclosed by the surface, carving away exterior tets.
|
|
15
|
+
* 3. The tet mesh is **compacted** — the carving pass leaves the free
|
|
16
|
+
* list populated with low-index slots, and downstream consumers
|
|
17
|
+
* (`tetrahedral_mesh_to_bvh` iterates by index, the shape's
|
|
18
|
+
* `recompute_cached` does the same) expect a hole-free range.
|
|
19
|
+
* Compaction relocates live tets so indices `[0, count)` are dense.
|
|
20
|
+
* 4. The flat positions + indices are kept verbatim on the shape for
|
|
21
|
+
* fast support-function and triangle-distance queries.
|
|
22
|
+
* 5. A {@link BVH} is built over the tet AABBs, used by
|
|
23
|
+
* {@link MeshShape3D#contains_point} for O(log N) point-in-mesh
|
|
24
|
+
* queries that correctly handle disconnected meshes (which the
|
|
25
|
+
* previous tet-walker did not).
|
|
26
|
+
*
|
|
27
|
+
* The caller's buffers are NOT cloned — they're attached to the shape
|
|
28
|
+
* directly. Don't mutate them after handing them in.
|
|
29
|
+
*
|
|
30
|
+
* @param {Float32Array} positions flat `(x, y, z)` per vertex
|
|
31
|
+
* @param {Uint32Array} indices three uint32 per triangle (CCW winding)
|
|
32
|
+
* @returns {MeshShape3D}
|
|
33
|
+
*/
|
|
34
|
+
export function shape_mesh_from_geometry(positions, indices) {
|
|
35
|
+
const shape = new MeshShape3D();
|
|
36
|
+
shape.positions = positions;
|
|
37
|
+
shape.indices = indices;
|
|
38
|
+
|
|
39
|
+
// 1. BinaryTopology from the indexed buffer.
|
|
40
|
+
const topology = new BinaryTopology();
|
|
41
|
+
bt_mesh_from_indexed_geometry(topology, indices, positions);
|
|
42
|
+
|
|
43
|
+
// 2. Tetrahedralise. interior_steiner_cells_per_dim = 0 — for
|
|
44
|
+
// collision queries the inside/outside oracle only needs
|
|
45
|
+
// surface-vertex tets; interior Steiner points add cost without
|
|
46
|
+
// changing the contains_point result.
|
|
47
|
+
shape.tet_positions = compute_tetrahedral_mesh_from_surface(shape.tet_mesh, topology, 0);
|
|
48
|
+
|
|
49
|
+
// 3. Compact. The carve pass freed slots in the tet mesh's
|
|
50
|
+
// allocator; compaction repacks live tets into a dense
|
|
51
|
+
// [0, count) range. Without this, `tetrahedral_mesh_to_bvh`
|
|
52
|
+
// iterates "tet index 0..count" and treats freed indices as if
|
|
53
|
+
// they were live tets — produces phantom BVH leaves with stale
|
|
54
|
+
// vertex data.
|
|
55
|
+
shape.tet_mesh.compact();
|
|
56
|
+
|
|
57
|
+
// 4. BVH over tet AABBs for the point-in-mesh query path.
|
|
58
|
+
tetrahedral_mesh_to_bvh(shape.tet_bvh, shape.tet_mesh, shape.tet_positions);
|
|
59
|
+
|
|
60
|
+
// 5. Refresh cached bbox / volume / surface area.
|
|
61
|
+
shape.recompute_cached();
|
|
62
|
+
|
|
63
|
+
return shape;
|
|
64
|
+
}
|
|
@@ -50,18 +50,16 @@ import { TetrahedralMesh } from "./TetrahedralMesh.js";
|
|
|
50
50
|
// radius-ratio metric.
|
|
51
51
|
const SLIVER_QUALITY_THRESHOLD = 0.05;
|
|
52
52
|
|
|
53
|
-
// Sliver-removal driver config.
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
53
|
+
// Sliver-removal driver config. The driver now builds a vertex→tet
|
|
54
|
+
// adjacency cache once per pass and shares it with the boundary check,
|
|
55
|
+
// the local quality eval, and the smoothing primitive — bringing per-pass
|
|
56
|
+
// cost from O(N²) down to O(N·deg). On a 3,242-tet densified cube the
|
|
57
|
+
// driver dropped from ~23 s to ~3 s; on closed-surface meshes (Suzanne,
|
|
58
|
+
// Teapot) where every vertex is boundary, smoothing is a near no-op and
|
|
59
|
+
// the pass should finish in well under a second.
|
|
59
60
|
//
|
|
60
|
-
//
|
|
61
|
-
|
|
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;
|
|
61
|
+
// BEFORE → AFTER numbers are logged in the per-mesh console line.
|
|
62
|
+
const ENABLE_IMPROVE_QUALITY = true;
|
|
65
63
|
const IMPROVE_TARGET_QUALITY = 0.05; // sliver cutoff only — keep the workload small
|
|
66
64
|
const IMPROVE_MAX_PASSES = 1;
|
|
67
65
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a `Map<vertex_id, tet_id[]>` enumerating every live tet that
|
|
3
|
+
* contains each vertex. One full pass over the mesh; the result lets
|
|
4
|
+
* subsequent per-vertex queries run in O(deg) instead of O(N).
|
|
5
|
+
*
|
|
6
|
+
* Useful when the caller is about to perform many per-vertex queries —
|
|
7
|
+
* e.g. boundary-status checks or 1-ring quality evaluations across a whole
|
|
8
|
+
* mesh during a quality-improvement pass. Without the cache, each query
|
|
9
|
+
* has to scan every live tet (see
|
|
10
|
+
* {@link tetrahedral_mesh_find_tets_attached_to_vertex} and
|
|
11
|
+
* {@link tetrahedral_mesh_vertex_is_boundary}), which compounds to O(N²)
|
|
12
|
+
* over a full pass.
|
|
13
|
+
*
|
|
14
|
+
* The map is a SNAPSHOT: it reflects mesh state at build time. Any flips,
|
|
15
|
+
* deletions or appends that happen afterwards will leave it stale. Callers
|
|
16
|
+
* must either rebuild after each mutation or accept the staleness (for
|
|
17
|
+
* boundary checks the cache is flip-invariant, so a once-per-pass rebuild
|
|
18
|
+
* is safe; for queries that need the exact current 1-ring, the caller
|
|
19
|
+
* should filter through `mesh.exists` and rebuild after mutations they
|
|
20
|
+
* care about).
|
|
21
|
+
*
|
|
22
|
+
* Cost: O(N) where N is `mesh.count`.
|
|
23
|
+
*
|
|
24
|
+
* @param {TetrahedralMesh} mesh
|
|
25
|
+
* @returns {Map<number, number[]>}
|
|
26
|
+
*/
|
|
27
|
+
export function tetrahedral_mesh_build_vertex_to_tets_map(mesh: TetrahedralMesh): Map<number, number[]>;
|
|
28
|
+
//# sourceMappingURL=tetrahedral_mesh_build_vertex_to_tets_map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tetrahedral_mesh_build_vertex_to_tets_map.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,kFAFa,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC,CAqBjC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { assert } from "../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build a `Map<vertex_id, tet_id[]>` enumerating every live tet that
|
|
5
|
+
* contains each vertex. One full pass over the mesh; the result lets
|
|
6
|
+
* subsequent per-vertex queries run in O(deg) instead of O(N).
|
|
7
|
+
*
|
|
8
|
+
* Useful when the caller is about to perform many per-vertex queries —
|
|
9
|
+
* e.g. boundary-status checks or 1-ring quality evaluations across a whole
|
|
10
|
+
* mesh during a quality-improvement pass. Without the cache, each query
|
|
11
|
+
* has to scan every live tet (see
|
|
12
|
+
* {@link tetrahedral_mesh_find_tets_attached_to_vertex} and
|
|
13
|
+
* {@link tetrahedral_mesh_vertex_is_boundary}), which compounds to O(N²)
|
|
14
|
+
* over a full pass.
|
|
15
|
+
*
|
|
16
|
+
* The map is a SNAPSHOT: it reflects mesh state at build time. Any flips,
|
|
17
|
+
* deletions or appends that happen afterwards will leave it stale. Callers
|
|
18
|
+
* must either rebuild after each mutation or accept the staleness (for
|
|
19
|
+
* boundary checks the cache is flip-invariant, so a once-per-pass rebuild
|
|
20
|
+
* is safe; for queries that need the exact current 1-ring, the caller
|
|
21
|
+
* should filter through `mesh.exists` and rebuild after mutations they
|
|
22
|
+
* care about).
|
|
23
|
+
*
|
|
24
|
+
* Cost: O(N) where N is `mesh.count`.
|
|
25
|
+
*
|
|
26
|
+
* @param {TetrahedralMesh} mesh
|
|
27
|
+
* @returns {Map<number, number[]>}
|
|
28
|
+
*/
|
|
29
|
+
export function tetrahedral_mesh_build_vertex_to_tets_map(mesh) {
|
|
30
|
+
assert.defined(mesh, 'mesh');
|
|
31
|
+
|
|
32
|
+
/** @type {Map<number, number[]>} */
|
|
33
|
+
const map = new Map();
|
|
34
|
+
|
|
35
|
+
mesh.forEach((tet, m) => {
|
|
36
|
+
for (let i = 0; i < 4; i++) {
|
|
37
|
+
const v = m.getVertexIndex(tet, i);
|
|
38
|
+
let bucket = map.get(v);
|
|
39
|
+
if (bucket === undefined) {
|
|
40
|
+
bucket = [];
|
|
41
|
+
map.set(v, bucket);
|
|
42
|
+
}
|
|
43
|
+
bucket.push(tet);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return map;
|
|
48
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tetrahedral_mesh_improve_quality.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tetrahedral_mesh_improve_quality.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js"],"names":[],"mappings":"AA2CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,gFApBW,YAAY,GAAC,MAAM,EAAE;qBAEV,MAAM;iBACV,MAAM;uBACA,MAAM;mBACV,OAAO;uBACH,OAAO;IAElB;IACZ,UAAc,EAAE,MAAM,CAAC;IACvB,oBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAqB,EAAE,MAAM,CAAC;CAC3B,CA8OH"}
|