The last-resort nudge's result is also measured finely; a face left a hair wide that meshes as its whole plane no longer passes as a plausible cut.
This commit is contained in:
1 parent
1a0b33fcf3
commit
5165e428cd
2 files changed
+43
-2
No files matched your search
@@ -1058,6 +1058,39 @@ fn a_ring_cut_round_a_hole_takes_in_the_hole_it_is_drawn_round() {
|
|||||||
assert!(if ok { rel(blind, taken) < 1e-3 } else { blind.abs() < 1e-6 }, "{ok} {blind} vs {taken}");
|
assert!(if ok { rel(blind, taken) < 1e-3 } else { blind.abs() < 1e-6 }, "{ok} {blind} vs {taken}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// #1360: an annulus cut 3 mm into a chamfered disc, its inner circle on a hole's wall. The
|
||||||
|
/// boolean can't intersect the two walls lying on each other; its last resort (the tool moved by
|
||||||
|
/// a micron) left a face a hair wide that meshes as its whole plane at a fine step, and the part
|
||||||
|
/// came back 21000 mm³ larger than before, a square plane across it. A cut may fail there, but it
|
||||||
|
/// never gives back more than it was given.
|
||||||
|
#[test]
|
||||||
|
fn a_cut_flush_with_a_hole_never_grows_the_part() {
|
||||||
|
let mut s = Session::default();
|
||||||
|
for (c, p) in [
|
||||||
|
("sketch.create", json!({"plane":"XY"})),
|
||||||
|
("sketch.circle.center", json!({"center":[0,0],"radius":40})),
|
||||||
|
("sketch.finish", json!({})),
|
||||||
|
("solid.extrude", json!({"distance":10})),
|
||||||
|
("solid.hole", json!({"position":[20,0,10],"diameter":6})),
|
||||||
|
("solid.chamfer", json!({"edges":[[40,0,10]],"distance":1})),
|
||||||
|
("sketch.create", json!({"plane":{"face":[0,0,10]}})),
|
||||||
|
("sketch.circle.center", json!({"center":[20,0],"radius":3})),
|
||||||
|
("sketch.circle.center", json!({"center":[20,0],"radius":6})),
|
||||||
|
("sketch.finish", json!({})),
|
||||||
|
] {
|
||||||
|
run(&mut s, c, p);
|
||||||
|
}
|
||||||
|
let before = volume(&mut s);
|
||||||
|
// Profile 2: the annulus between the hole's wall and the larger circle.
|
||||||
|
let r = s.execute("solid.extrude", &json!({"direction":"negative","distance":"3","operation":"cut","profiles":[2]}));
|
||||||
|
let after = volume(&mut s);
|
||||||
|
let ring = std::f64::consts::PI * (36.0 - 9.0) * 3.0;
|
||||||
|
match r {
|
||||||
|
Ok(_) => assert!(rel(before - after, ring) < 1e-2, "{before} -> {after}, want {ring} taken"),
|
||||||
|
Err(_) => assert!(rel(after, before) < 1e-9, "{before} -> {after} after a failed cut"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A line of text cut into a face: the letters' curves (the font's quadratics) are read
|
/// A line of text cut into a face: the letters' curves (the font's quadratics) are read
|
||||||
/// exactly, and the cut is decided in 2D in one boolean, at any depth and where the text runs
|
/// exactly, and the cut is decided in 2D in one boolean, at any depth and where the text runs
|
||||||
/// off the face. The B-rep boolean failed on many letters at once ("no result" at 3.5 mm, and
|
/// off the face. The B-rep boolean failed on many letters at once ("no result" at 3.5 mm, and
|
||||||
|
|||||||
@@ -956,15 +956,23 @@ fn boolean_whole(a: &Body, b: &Body, op: BoolOp) -> Result<Option<Body>> {
|
|||||||
match r {
|
match r {
|
||||||
Ok(Some(body)) => {
|
Ok(Some(body)) => {
|
||||||
let (ok, v) = check(&body);
|
let (ok, v) = check(&body);
|
||||||
if ok {
|
// Measured finely too: a face the boolean left a hair wide, its loops a hair
|
||||||
|
// apart, can mesh as its whole plane at a fine step though it meshed as a sliver
|
||||||
|
// at the check's (#1360: an annulus cut flush with a hole's wall came out 21000
|
||||||
|
// mm³ larger than the part it was cut from, a square plane across it).
|
||||||
|
let fine_ok = ok && crate::measure(&body).is_ok_and(|m| plausible(m.volume, op, va, vb, slack));
|
||||||
|
if ok && !fine_ok {
|
||||||
|
last = format!("{last}; the nudged tool gave a solid whose faces mesh inconsistently");
|
||||||
|
} else if ok {
|
||||||
merge(diagnostics);
|
merge(diagnostics);
|
||||||
let mut event = BooleanFallback::new(BooleanStrategy::ToolNudge);
|
let mut event = BooleanFallback::new(BooleanStrategy::ToolNudge);
|
||||||
event.translation_mm = translation.len();
|
event.translation_mm = translation.len();
|
||||||
event.rotation_rad = 2e-6;
|
event.rotation_rad = 2e-6;
|
||||||
record(event);
|
record(event);
|
||||||
return Ok(Some(body));
|
return Ok(Some(body));
|
||||||
|
} else {
|
||||||
|
last = format!("{last}; the nudged tool gave an implausible volume {v:.4}");
|
||||||
}
|
}
|
||||||
last = format!("{last}; the nudged tool gave an implausible volume {v:.4}");
|
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
merge(diagnostics);
|
merge(diagnostics);
|
||||||
|
|||||||
Reference in new issue
Block a user