mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 19:15:57 +00:00
Kernel tests: modifier histories are graded by what each face is, not how many changed
Three history tests pinned truck's sewing in tallies: - shell_of_a_painted_body wanted changes [0, 2, 8, 0, 5], the side faces split across the rim's level; SMLib's shell leaves them whole. It now checks what paint follows: the painted face 0 comes through as exactly one face (its geometry checked against face 0 by verified()), and each of the five inner walls is one Generated Offset of the face it lines, the open top none, as shell_lines_the_walls_with_offsets has it. - fillet_after_box_cuts wanted the painted cuts to leave faces in pieces and the fillet's edges to meet merged faces; it keeps the outcome for every cut on both blocks: the round stands in place of the picked edge, and composed with the cut the history holds over the block and the tool. merged_meetings has no use left and goes. - surfaces_keep_their_faces wanted every stitched face Kept; whether sewing changes a face's class is not the contract. It now checks each stitched face has one origin, the face it was sewn from (geometry checked by checked()), the five walls the open box's faces 0-4 and the lid the patch, and the four seams naming two edges each. split_a_face is left as it is (the owner's ruling: a face whose boundary only gained a vertex is Kept), failing until SolidCraft's split history says so ([3, 2, 2, 0, 0] against [5, 0, 2, 0, 0]). The three tests above pass today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -263,15 +263,23 @@ fn shell_of_a_stepped_body_joins_its_walls() {
|
||||
assert_eq!(offsets, b.face_count() - 1, "{h:?}");
|
||||
}
|
||||
|
||||
/// A shell of a painted block: its faces are used as they are (unhealed), keeping the paint's
|
||||
/// face order, with the history of that copy. Paint is an authored boundary, so the cavity Cut
|
||||
/// keeps the side faces it sews across the rim's level in pieces (Split).
|
||||
/// A shell of a painted block: the painted face (face 0) comes through as one face on its own
|
||||
/// support, so the paint has one face to follow, and each of the five inner walls is an offset of
|
||||
/// the face it lines, as on the plain block (`shell_lines_the_walls_with_offsets`).
|
||||
#[test]
|
||||
fn shell_of_a_painted_body() {
|
||||
let b = painted_cube();
|
||||
let r = crate::shell(&b, &[Vec3::new(20.0, 15.0, 20.0)], 2.0).unwrap();
|
||||
let top = Vec3::new(20.0, 15.0, 20.0);
|
||||
let r = crate::shell(&b, &[top], 2.0).unwrap();
|
||||
let h = verified(&r, &b, reach(2.0));
|
||||
assert_eq!(changes(h), [0, 2, 8, 0, 5], "{h:?}");
|
||||
assert_eq!(with(h, &[face(0)]).len(), 1, "the painted face is one face: {h:?}");
|
||||
let top = face_at(&b, top);
|
||||
for f in (0..6).filter(|f| *f != top) {
|
||||
let walls = with(h, &[FaceOrigin::Offset { operand: 0, face: f }]);
|
||||
assert_eq!(walls.len(), 1, "{h:?}");
|
||||
assert_eq!(h.faces[walls[0]].change, Change::Generated);
|
||||
}
|
||||
assert!(with(h, &[FaceOrigin::Offset { operand: 0, face: top }]).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -370,10 +378,22 @@ fn surfaces_keep_their_faces() {
|
||||
let h = checked(&lid, &[&open], reach(0.0), &|_| true);
|
||||
assert_eq!(h.faces[0].change, Change::Generated);
|
||||
assert!(h.edges.iter().all(|e| matches!(e.origins.as_slice(), [EdgeOrigin::Edge { operand: 0, .. }])));
|
||||
// Stitched: each face the one it was sewn from, the seam the edges sewn together.
|
||||
// Stitched: each face the one it was sewn from (its geometry checked against it), the five
|
||||
// walls each one of the open box's and the lid the patch, and the seam the edges sewn
|
||||
// together.
|
||||
let closed = crate::stitch(&[&open, &lid], 0.0).unwrap();
|
||||
let h = checked(&closed, &[&open, &lid], reach(0.0), &|_| false);
|
||||
assert!(h.faces.iter().all(|f| f.change == Change::Kept && f.origins.len() == 1));
|
||||
let mut sewn: Vec<FaceOrigin> = h
|
||||
.faces
|
||||
.iter()
|
||||
.map(|f| match f.origins[..] {
|
||||
[o] => o,
|
||||
_ => panic!("a stitched face from one face: {f:?}"),
|
||||
})
|
||||
.collect();
|
||||
sewn.sort();
|
||||
let want = [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0)].map(|(operand, face)| FaceOrigin::Face { operand, face });
|
||||
assert_eq!(sewn, want, "{h:?}");
|
||||
assert_eq!(h.edges.iter().filter(|e| e.origins.len() == 2).count(), 4);
|
||||
let patch = crate::patch_region(&Plane::XY, &Region2 { outer: square(0.0, 0.0, 10.0, 10.0), holes: vec![] }).unwrap();
|
||||
assert_eq!(patch.history().unwrap().operands, 0);
|
||||
@@ -432,29 +452,16 @@ fn box_cuts_of(b: &Body) -> Vec<(&'static str, Body, Body)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Meetings with a side of several origins (a face the modifier's heal merged).
|
||||
fn merged_meetings(h: &History) -> usize {
|
||||
h.edges.iter().flat_map(|e| &e.origins).filter(|o| matches!(o, EdgeOrigin::Meet { a, b } if a.single().is_none() || b.single().is_none())).count()
|
||||
}
|
||||
|
||||
/// A fillet right after a box cut. The cut joins the walls it sews in pieces across its slabs
|
||||
/// on their common supports, so the fillet finds whole faces. Where the block is painted the cut
|
||||
/// keeps those pieces (it has more faces), the fillet's heal merges them, and the edges where
|
||||
/// the round runs into such a face meet all of it. Composed with the cut, over the block and
|
||||
/// the tool.
|
||||
/// A fillet right after a box cut, on the plain and the painted block: the round stands in place
|
||||
/// of the picked edge, and composed with the cut its history holds over the block and the tool.
|
||||
#[test]
|
||||
fn fillet_after_box_cuts() {
|
||||
let at = Vec3::new(5.0, 0.0, 20.0);
|
||||
let plain = box_cuts_of(&cube());
|
||||
for (b, painted) in [(cube(), false), (painted_cube(), true)] {
|
||||
let cuts = if painted { box_cuts_of(&b) } else { plain.clone() };
|
||||
for ((name, cut, tool), (_, whole, _)) in cuts.into_iter().zip(&plain) {
|
||||
for (name, cut, tool) in box_cuts_of(&b) {
|
||||
let r = crate::fillet(&cut, &[at], 2.0).unwrap();
|
||||
let h = verified(&r, &cut, reach(2.0 * 1.5));
|
||||
assert_eq!(blends(h), [vec![edge(edge_at(&cut, at))]], "{name}");
|
||||
let pieces = cut.face_count() > whole.face_count();
|
||||
assert_eq!(pieces, painted && name != "notch" && name != "hole", "{name} (painted: {painted})");
|
||||
assert_eq!(merged_meetings(h) > 0, pieces, "{name} (painted: {painted}): {h:?}");
|
||||
assert_eq!(blends(h), [vec![edge(edge_at(&cut, at))]], "{name} (painted: {painted})");
|
||||
let mut through = h.clone();
|
||||
through.substitute(0, cut.history().unwrap()).unwrap();
|
||||
through.check(&r, &[&b, &tool]).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user