Face counts: classify sliver faces from their exact surface (#308) (#357)

Since 4e595de a partial-depth cut that ends inside a cylinder runs through the
exact stacked-section path, which leaves 0.3 mm wide strips of the cylinder wall
beside the cut. Their tessellation is one triangle wide, too few distinct
samples for the cylinder fit, so the merged topology reported them as a sphere
and a freeform face. Where the mesh fit finds no plane or cylinder, use the
face's exact surface (plane, cylinder or sphere) instead.

Fixes #308


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

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-12 14:35:13 -04:00
1 parent d15869ab85
commit 882ef0e9c6
2 files changed
+52 -5

No files matched your search

+27
View File
@@ -185,3 +185,30 @@ fn repeated_source_face_profile_requires_and_uses_the_exact_active_occurrence()
assert!(!state.bodies.iter().any(|body| body.body.contains(Vec3::new(x, 5.0, 16.0))));
}
}
/// #308: a blind cut ending inside a cylinder leaves thin strips of the cylinder wall beside
/// the cut; they must count as cylinder, not as a sphere or a freeform face.
#[test]
fn blind_cut_inside_a_cylinder_keeps_only_planes_and_cylinders() {
let mut s = Session::default();
let side = json!({"origin":[0,0,0],"x_dir":[0,0,-1],"y_dir":[0,1,0]});
s.execute("solid.box", &json!({"length":40,"width":30,"height":3,"body_name":"Hinge"})).unwrap();
for (name, radius, operation, extent) in
[("Knuckle", 4, "join", json!({"distance":40})), ("Pin", 2, "cut", json!({"distance":100,"direction":"symmetric"}))]
{
s.execute("sketch.create", &json!({"name":name,"plane":side})).unwrap();
s.execute("sketch.circle.center", &json!({"center":[-4,33],"radius":radius})).unwrap();
s.execute("sketch.finish", &json!({})).unwrap();
let mut p = json!({"sketch":name,"operation":operation,"body_names":["Hinge"]});
p.as_object_mut().unwrap().extend(extent.as_object().unwrap().clone());
s.execute("solid.extrude", &p).unwrap();
}
s.execute("sketch.create", &json!({"name":"Gap","plane":"XY"})).unwrap();
s.execute("sketch.rectangle.two_point", &json!({"p0":[12,29],"p1":[28,40]})).unwrap();
s.execute("sketch.finish", &json!({})).unwrap();
s.execute("solid.extrude", &json!({"sketch":"Gap","operation":"cut","distance":3.3,"body_names":["Hinge"]})).unwrap();
let m = s.execute("inspect.measure", &json!({})).unwrap();
let body = &m["bodies"][0];
assert_eq!(body["face_types"], json!({"cylinder": 2, "plane": 12}), "{m}");
assert_eq!(body["faces"], 14, "{m}");
}