Lip: run along the rim's opening, not the foot of a boss standing on the face (#933)

A lip picked on a face that isn't a shelled body's rim, such as the Sample Plate's top
face with its two holes and the boss standing on it, ran its band round the largest inner
edge. That was the boss's foot, so the band stood against the boss's wall and the join
failed with a boolean error about curved faces.

The band now goes round the face's opening (an inner edge with no material just over the
face inside it). A rim face that has a smaller hole in it still works. A face whose inner
edges are only where other features stand on it, or whose openings are alike in size (a
plate's holes), is refused with a plain message that names the rim face it needs.

Fixes #892.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-13 20:26:24 -04:00
1 parent 2dcfea8df7
commit b41ad23e3f
2 files changed
+44 -2

No files matched your search

+18
View File
@@ -336,6 +336,24 @@ mod tests {
assert!(g.execute("plastic.lip", &json!({"face": [40, 25, 0], "width": 1, "height": 2})).is_err(), "a face without an inner edge");
}
#[test]
fn lip_on_a_face_that_is_not_a_rim_says_so() {
// The Sample Plate's top face (#892): two holes through it and the boss standing on it.
// The lip used to run round the boss's foot, against its wall, and the join failed in
// the boolean; it is refused as no rim instead.
let mut s = Session::default();
s.run_script(&crate::sample::script()).unwrap();
let lip = json!({"body": "Plate", "face": [51.89, 45.2, 8.0], "width": "1.5 mm", "height": "3.5 mm", "side": "inside", "type": "lip"});
let e = s.execute("plastic.lip", &lip).unwrap_err().to_string();
assert!(e.contains("rim face") && e.contains("2 openings alike"), "{e}");
// The boss alone, no holes: its foot is not an opening either.
let mut b = Session::default();
run(&mut b, "solid.box", json!({"length": 80, "width": 50, "height": 8, "body_name": "Plate"}));
run(&mut b, "solid.cylinder", json!({"base": [40, 25, 8], "axis": [0, 0, 1], "radius": 12, "height": 14, "operation": "join"}));
let e = b.execute("plastic.lip", &lip).unwrap_err().to_string();
assert!(e.contains("stand on it"), "{e}");
}
#[test]
fn snap_fit_arm_and_catch() {
let mut s = Session::default();