Kernel/refine mesh for curved meeting (#1812)

Thanks @Ian-cmd-ops.
This commit is contained in:
H. Conrad authored and GitHub committed 2026-10-17 04:07:33 -04:00
1 parent 2abf4e5a7d
commit 221e841d32
2 files changed
+36 -4

No files matched your search

+34 -2
View File
@@ -512,6 +512,15 @@ fn meeting_size(a: &Body, b: &Body) -> f64 {
if s.x > 0.0 && s.y > 0.0 && s.z > 0.0 { s.x.min(s.y).min(s.z) } else { f64::INFINITY }
}
/// Smallest side of the box where the bounds of two meshes overlap (infinite when they don't).
/// Unlike [`meeting_size`], this follows curved faces: a cylinder's vertices are only the points
/// on its seam, so its vertex box says nothing about where its side reaches.
fn mesh_meeting_size(a: &solidcraft_geom::Mesh, b: &solidcraft_geom::Mesh) -> f64 {
let (ba, bb) = (a.bounds(), b.bounds());
let s = solidcraft_geom::Aabb3 { min: ba.min.max(bb.min), max: ba.max.min(bb.max) }.size();
if s.x > 0.0 && s.y > 0.0 && s.z > 0.0 { s.x.min(s.y).min(s.z) } else { f64::INFINITY }
}
/// Whether a result volume is plausible for `op`: within the bounds the operands' volumes
/// leave, plus the slack the meshed volumes are measured to.
fn plausible(v: f64, op: BoolOp, va: f64, vb: f64, slack: f64) -> bool {
@@ -586,7 +595,7 @@ fn boolean_whole_with_refinement(a: &Body, b: &Body, op: BoolOp, refine: bool) -
// refined: a round side trimmed to a thin band (a short boss crossing a gently sloping
// floor) is otherwise spanned by triangles cutting through it, which reads as missing
// material.
let tol_m = (size * 5e-4).min(meeting_size(a, b) * 2e-3).max(size * 1e-5);
let mut tol_m = (size * 5e-4).min(meeting_size(a, b) * 2e-3).max(size * 1e-5);
// A prism pair (a plate and the tool through it) is decided exactly in 2D, with no mesh of
// either operand. The sampled shortcuts below need a refined mesh of both, and that mesh is
// most of what a boolean costs: a pattern or a multi-profile sketch rebuilds the whole
@@ -610,7 +619,30 @@ fn boolean_whole_with_refinement(a: &Body, b: &Body, op: BoolOp, refine: bool) -
return Ok(Some(body.clone()));
}
}
let meshes = (a.tessellate_with(tol_m, true).ok(), b.tessellate_with(tol_m, true).ok());
let mut meshes = (a.tessellate_with(tol_m, true).ok(), b.tessellate_with(tol_m, true).ok());
// The vertex boxes above miss a curved operand's reach (a cylinder has only seam vertices),
// so a thin meeting region of curved bodies kept the coarse step: a sliver 0.5 mm thick was
// faceted at 0.017 mm and a correct result failed the membership test. The meshes just made
// do span the bodies, so the step is set again from where they meet and the meshes are
// remade once, when that is a much finer step.
let refined = match &meshes {
// A meeting box only a few steps thick is the tessellation error of bodies that merely
// touch or miss each other: a finer mesh there cannot help and only slows the operation.
(Some(ma), Some(mb)) => {
let meet = mesh_meeting_size(ma, mb);
(meet > tol_m * 8.0).then(|| (size * 5e-4).min(meet * 2e-3).max(size * 1e-5))
}
_ => None,
};
if let Some(refined) = refined
&& refined < tol_m * 0.5
{
let again = (a.tessellate_with(refined, true).ok(), b.tessellate_with(refined, true).ok());
if again.0.is_some() && again.1.is_some() {
tol_m = refined;
meshes = again;
}
}
let (va, vb) = match &meshes {
(Some(ma), Some(mb)) => (ma.measure().volume, mb.measure().volume),
_ => (volume(a), volume(b)),
+2 -2
View File
@@ -285,9 +285,9 @@ fn check(r: Result<(), TestCaseError>) {
}
}
/// A box and a cylinder in general position: the intersect is refused as an implausible volume.
/// A box and a cylinder in general position: the intersect is a sliver 0.5 mm thick. It was
/// refused as an implausible volume, because the meshes of the check were faceted at 0.017 mm.
#[test]
#[ignore = "kernel bug, #1647"]
fn generic_box_cylinder_intersect() {
let a = Prim::Box { at: [11.483767761089219, 4.801612107504224, 3.6313476467611787], size: [4.789088988834864, 3.0, 10.419335961063835] };
let b = Prim::Cyl { at: [29.2480632732879, 8.3683289461485, 6.947922225984966], axis: 2, r: 13.502884497756853, h: 19.719218725477496 };