From 39e1dcea0397c192c73df09d3451b026334123da Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Thu, 29 Oct 2026 01:02:38 -0400 Subject: [PATCH] Faceted boolean: a body's own mesh is closed once its faces' shared corners are one vertex faceted_boolean took the tool mesh's triangles by vertex index and refused any edge not shared by exactly two triangles. A body's mesh (Body::mesh) gives each face its own vertices, the faces along an edge the very same points, so a box's mesh came in as six open patches: "the mesh is not closed". Corners at the very same point are now one vertex first (triangles keep their order, so the history's triangle faces are unchanged). Co-Authored-By: Claude Opus 5.5 --- crates/kernel/src/polybool.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/kernel/src/polybool.rs b/crates/kernel/src/polybool.rs index a722c1882b..59deb92792 100644 --- a/crates/kernel/src/polybool.rs +++ b/crates/kernel/src/polybool.rs @@ -39,6 +39,8 @@ fn faceted_boolean_untimed(a: &Body, b: &Mesh, op: BoolOp, tol: f64) -> Result MAX_TRIANGLES { return Err(failed(&format!("the mesh is too detailed ({} triangles, at most {MAX_TRIANGLES})", b.triangles.len()))); } + let welded = welded(b); + let b = &welded; let groups = coplanar_groups(b, tol)?; let mut faces = Vec::new(); let mut face_group = Vec::new(); @@ -60,6 +62,26 @@ fn faceted_boolean_untimed(a: &Body, b: &Mesh, op: BoolOp, tol: f64) -> Result Mesh { + let mut at: BTreeMap<[u64; 3], u32> = BTreeMap::new(); + let mut positions = Vec::with_capacity(m.positions.len()); + let index: Vec = m + .positions + .iter() + .map(|p| { + *at.entry([p.x.to_bits(), p.y.to_bits(), p.z.to_bits()]).or_insert_with(|| { + positions.push(*p); + (positions.len() - 1) as u32 + }) + }) + .collect(); + let triangles = m.triangles.iter().map(|t| t.map(|i| index.get(i as usize).copied().unwrap_or(i))).collect(); + Mesh { positions, triangles, ..Mesh::default() } +} + /// The mesh's triangles in runs that make one planar face each: triangles sharing an edge, on /// one plane within `tol`, are one run. fn coplanar_groups(m: &Mesh, tol: f64) -> Result>> {