Tests: the saved curved strip is the link a truck build saved

saved_curved_strip_projection_is_lost_after_exact_wall_coalescence built its "old" strip by
cutting the cavity raw (paint turning off the construction shortcut), where truck sewed the cut
slab by slab and split the outer round at the cavity's floor. SMLib cuts without slabs: the raw
cut's round is one face, so there was no piece to save a projection on, and the test stopped at
"must have a piece suffix". The link is now what such a build saved, written out: the face name
`F2:blend:F1:+x|F1:+y#1` (the lower piece, numbered up its spread) and the piece's projection on
YZ, the rectangle y 24..30, z 0..2 (the quarter round from (40, 24) to (34, 30), its arcs and
straight sides), 12 mm³ when extruded 1. The current wall is checked to be one face with that
stem and no planar authority.

The test still fails: the link is found on the whole wall ("was split; using the nearest
piece"), not lost, and the strip's material grows to 6 × 30 × 1 = 180 mm³. project.rs takes a
missing piece as removed only on a certified planar or coalesced face, which truck's shell
made and SMLib's does not. That is a persistent-name decision for the owner (see the PR).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-29 22:55:55 -04:00
committed by Irakli Kourtis
parent a3f150257f
commit 01477bb143
+22 -70
View File
@@ -309,7 +309,6 @@ fn saved_former_strip_projection_reports_lost_without_expanding_healthy_material
#[test]
fn saved_curved_strip_projection_is_lost_after_exact_wall_coalescence() {
use solidcraft_kernel::{FacePaint, Paint};
use solidcraft_sketch::{LinkKind, LinkSource, Sketch};
let mut doc = Document::new("saved curved strip");
doc.set_param("width", "80", Some("mm"), None).unwrap();
@@ -327,86 +326,39 @@ fn saved_curved_strip_projection_is_lost_after_exact_wall_coalescence() {
Some("Corners"),
)
.unwrap();
let shell = doc
.add_feature(
FeatureKind::Shell {
faces: vec![crate::FacePick(Vec3::new(0., 0., 30.))],
thickness: "wall".into(),
body: Some("Case".into()),
direction: "inside".into(),
tangent_chain: false,
},
Some("Shell"),
)
.unwrap();
doc.add_feature(
FeatureKind::Shell {
faces: vec![crate::FacePick(Vec3::new(0., 0., 30.))],
thickness: "wall".into(),
body: Some("Case".into()),
direction: "inside".into(),
tangent_chain: false,
},
Some("Shell"),
)
.unwrap();
let mut model = Model::new();
model.evaluate(&doc);
assert!(model.results.iter().all(|r| r.error.is_none()), "{:?}", model.results);
let before = model.state_before(shell);
// Per-face paint disables the construction optimization: this control keeps
// the real pre-repair slab faces without forging a name or source witness.
let old_source = before
.body("Case")
.unwrap()
.body
.clone()
.with_paint(Some(Paint { opacity: 1., faces: vec![FacePaint { face: 0, color: [1., 0., 0.], opacity: 1. }] }));
let cavity_box = solidcraft_kernel::box_solid(Vec3::new(-38., -28., 2.), Vec3::new(38., 28., 35.)).unwrap();
let cavity = solidcraft_kernel::fillet(
&cavity_box,
&[Vec3::new(38., 28., 15.), Vec3::new(-38., 28., 15.), Vec3::new(-38., -28., 15.), Vec3::new(38., -28., 15.)],
4.,
)
.unwrap();
let raw = solidcraft_kernel::boolean(&old_source, &cavity, solidcraft_kernel::BoolOp::Cut).unwrap().unwrap();
let mut old_body = ModelBody::new("Case".into(), raw, shell);
old_body.names = crate::naming::NameCell::new(Some(std::sync::Arc::new(crate::naming::NamingOrigin {
feature: doc.feature(shell).unwrap().clone(),
before,
depth: 1,
mats: vec![],
sheets: vec![],
})));
// A point low on the outer round of the +x+y corner (radius 6 about (34, 24)), below the
// cavity's floor at z = 2.
let t = std::f64::consts::FRAC_1_SQRT_2;
let at = Vec3::new(34. + 6. * t, 24. + 6. * t, 1.);
let former = crate::naming::face_name_at_body(&old_body, at).unwrap();
let stem = crate::naming::strip_piece(&former).to_string();
assert_ne!(former, stem, "actual old cylindrical strip must have a piece suffix");
let state = model.state();
let current = state.body("Case").unwrap();
let names = crate::naming::face_names(current);
let stem = crate::naming::face_name_at_body(current, at).unwrap();
assert_eq!(crate::naming::strip_piece(&stem), stem, "the shelled wall's round is one exact face, floor to rim");
let index = names.iter().position(|name| name == &stem).unwrap();
assert!(current.body.face_was_coalesced(index));
assert!(current.body.face_plane(index).is_none(), "witness grants no planar attachment authority");
assert!(old_body.body.face_sources().is_none_or(|sources| sources.iter().enumerate().all(|(index, _)| !old_body.body.face_was_coalesced(index))));
let mut old_state = (*model.state()).clone();
old_state.bodies = vec![old_body];
// What a build that sewed the cut slab by slab saved: the round in two pieces split at the
// cavity's floor, the projection made on the lower one, `#1` (pieces numbered up their
// longest spread), from z = 0 to 2. Projected on YZ, the quarter round from (40, 24) to
// (34, 30) is the rectangle y 24..30, z 0..2: its two arcs and its two straight sides.
let former = format!("{stem}#1");
let source = LinkSource::Face { body: "Case".into(), at };
// Recover the saved projection from the old face's complete raw topology.
// Display seam suppression must not discard a historical strip boundary.
let old_body = old_state.body("Case").unwrap();
let old_index = crate::naming::face_on_body(old_body, &former, at).unwrap().0;
let mesh = old_body.mesh();
let mut geometry = Vec::new();
for (index, faces) in mesh.edge_faces.iter().enumerate() {
if !faces.contains(&(old_index as u32)) {
continue;
}
let points = &mesh.edges[index];
let a = solidcraft_geom::Plane::YZ.to_local(*points.first().unwrap());
let b = solidcraft_geom::Plane::YZ.to_local(*points.last().unwrap());
let (a, b) = (Vec2::new(a.x, a.y), Vec2::new(b.x, b.y));
assert!(a.dist(b) > 1e-6);
for point in points {
let q = solidcraft_geom::Plane::YZ.to_local(*point);
let q = Vec2::new(q.x, q.y);
let direction = b - a;
let t = ((q - a).dot(direction) / direction.dot(direction)).clamp(0., 1.);
assert!(q.dist(a + direction * t) < 1e-7, "exact cylindrical quadrant projects to a straight support");
}
geometry.push(solidcraft_sketch::LinkGeom::Line(a, b));
}
assert_eq!(geometry.len(), 4, "historical curved strip has a complete four-edge rectangular projection");
let (a, b, c, d) = (Vec2::new(24., 0.), Vec2::new(30., 0.), Vec2::new(30., 2.), Vec2::new(24., 2.));
let geometry: Vec<_> = [(a, b), (b, c), (c, d), (d, a)].into_iter().map(|(p, q)| solidcraft_sketch::LinkGeom::Line(p, q)).collect();
let mut sketch = Sketch::new();
sketch.add_link(LinkKind::Project, source, &geometry).unwrap();
sketch.links[0].face_name = Some(former);