1 parent
2abf4e5a7d
commit
221e841d32
2 files changed
+36
-4
No files matched your search
@@ -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)),
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in new issue
Block a user