UI tests: SMLib's cylinder has one wall and one edge per rim; split rims come from two arcs

truck made a cylinder's wall and rims in halves; SMLib makes one wall face and one closed edge
per rim (one face per profile segment, a circle being one closed curve since 09c979a4b). The
tests of what joins a rim's or a wall's pieces for picking, measuring and the agent chat
(circular_rim_hover_click..., circular_items_measure..., curved_face_hover..._cross_the_seam,
a_rim_clicked_once_is_one_item_not_its_pieces) now build their cylinder from a circle drawn as
two half arcs, extruded, so the pieces they test exist. A ring's outer circle is one wall face
(configuration_annulus_picker...: 1, was 2). The certified small crease is no longer taken for
a seam (truck's coarse fit did; the seam flags compare exact surfaces now) and, a kink of a
millionth, is smooth for the shading while still a measured crease: sharp, drawn in wireframe,
picked (smooth_edges::Join).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-28 22:44:48 -04:00
committed by Irakli Kourtis
parent ff0dda5377
commit 2523d13cf0
3 changed files with 34 additions and 9 deletions
+7 -2
View File
@@ -2293,12 +2293,17 @@ fn the_picks_go_with_the_next_message_once() {
}
/// Two clicks on two rims are two things, not four edges (a click on a rim selects both halves for
/// the commands; the chat counts and describes what was clicked).
/// the commands; the chat counts and describes what was clicked). The cylinder is a circle drawn
/// as two half arcs, extruded, so each rim is in two halves.
#[test]
fn a_rim_clicked_once_is_one_item_not_its_pieces() {
use solidcraft_engine::Sel;
let (mut app, script, ctx) = app_with_script();
app.run("solid.cylinder", json!({"radius": 10, "height": 20})).expect("a cylinder");
app.run("sketch.create", json!({"plane": "XY"})).expect("a sketch");
app.run("sketch.arc.three_point", json!({"start": [10, 0], "end": [-10, 0], "through": [0, 10]})).expect("an arc");
app.run("sketch.arc.three_point", json!({"start": [-10, 0], "end": [10, 0], "through": [0, -10]})).expect("an arc");
app.run("sketch.finish", json!({})).expect("the sketch");
app.run("solid.extrude", json!({"distance": 20})).expect("a cylinder");
let (name, top, bottom, mid_top, mid_bottom) = {
let st = crate::open_meshing::session_world(&app.session);
let body = &st.bodies[0];
+3 -2
View File
@@ -1103,10 +1103,11 @@ mod tests {
assert!(matches!(&target.certificate, Some(solidcraft_engine::doc::config::FaceCertificate::ExtrudeSide { curve, .. }) if curve == "outer"));
let state = h.app.session.model.state();
let body = state.body("Ring").unwrap();
// The outer circle, one closed curve, is one wall face.
let indices = h.app.session.doc.configuration_face_indices(body, target).unwrap();
assert_eq!(indices.len(), 2);
assert_eq!(indices.len(), 1);
let painted = h.app.session.doc.face_colors(body);
assert_eq!(painted.len(), 2);
assert_eq!(painted.len(), 1);
assert!(painted.iter().all(|(index, _)| indices.contains(index)));
}
+24 -5
View File
@@ -8304,6 +8304,21 @@ mod tests {
app
}
/// A Ø20 × 20 cylinder whose wall and rims are each in two halves: a circle drawn as two
/// half arcs, extruded (one wall face per arc). SMLib's own cylinder has one wall and one
/// edge per rim; a rim or wall in pieces comes from a profile like this one or an import.
fn split_cylinder_app() -> SolveApp {
let mut s = solidcraft_engine::Session::default();
s.execute("sketch.create", &json!({"plane": "XY"})).unwrap();
s.execute("sketch.arc.three_point", &json!({"start": [10, 0], "end": [-10, 0], "through": [0, 10]})).unwrap();
s.execute("sketch.arc.three_point", &json!({"start": [-10, 0], "end": [10, 0], "through": [0, -10]})).unwrap();
s.execute("sketch.finish", &json!({})).unwrap();
s.execute("solid.extrude", &json!({"distance": 20})).unwrap();
let mut app = SolveApp::new(s, crate::Services::default());
app.set_origin_shown(false);
app
}
/// Moving the pointer across a face keeps its highlight (a scanned mesh is one face of
/// millions of triangles): only another face, edge or plane builds it again.
#[test]
@@ -8642,9 +8657,13 @@ mod tests {
})
})
.unwrap();
assert!(mesh.seams[crease], "the fixture must exercise the coarse seam false positive");
// Truck's coarse seam fit took this crease for a seam between pieces of one surface;
// the seam flags now compare the exact surfaces (`topo::seam_flags`). Either way the
// certified crease is sharp, drawn in wireframe and picked. Its kink of a millionth is
// too close to tangent to show in the shading (`smooth_edges::Join`: smooth and a
// measured crease at once), so the shaded view leaves it out.
assert!(mesh.sharp_edges[crease]);
assert!(mesh.shaded_edge_visible(crease));
assert!(mesh.edge_visible(crease) && !mesh.shaded_edge_visible(crease));
assert!(mesh.edge_pickable(crease));
assert!(mesh.edge_faces[crease].iter().any(|f| mesh.surface_patch(*f as usize).len() == 1));
let mid = polyline_mid(&mesh.edges[crease]);
@@ -8660,7 +8679,7 @@ mod tests {
#[test]
fn circular_items_measure_as_whole_rims_and_surfaces() {
let mut app = cylinder_app();
let mut app = split_cylinder_app();
let st = app.session.world_state().unwrap();
let b = &st.bodies[0];
let m = b.mesh();
@@ -8741,7 +8760,7 @@ mod tests {
#[test]
fn circular_rim_hover_click_and_dialog_pick_include_both_halves() {
let mut app = cylinder_app();
let mut app = split_cylinder_app();
let st = app.session.world_state().unwrap();
let b = &st.bodies[0];
let m = b.mesh();
@@ -8788,7 +8807,7 @@ mod tests {
#[test]
fn curved_face_hover_selection_and_dialogs_cross_the_seam() {
let mut app = cylinder_app();
let mut app = split_cylinder_app();
let st = app.session.world_state().unwrap();
let b = &st.bodies[0];
let m = b.mesh();