From 785b78bea549fdcac8fd831ed830ebcbbf811546 Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Fri, 30 Oct 2026 02:30:05 -0400 Subject: [PATCH] Surface Fair test: fair the B-spline patch on a saddle rim, not an offset sphere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test offset the sphere's top patch to get a fitted B-spline sheet. That held on truck, whose sphere came in several patches and whose sphere offset was fitted. On SMLib the sphere is one face: offsetting it closes up, so it is a solid by design (surface_offset.rs, "Faces that close up make a solid", and its test a_sphere_is_fitted_and_refused_past_its_centre asserts exactly that), and SMLib's offset is exact, a sphere of radius 22 with no control points, which surface.fair refuses. Body::is_surface was right: the record lists the offset's closed shell as the outer shell of a material region (Parts::canonical), so it is a solid whether read from edge uses or from regions. The test now fairs the patch on the non-planar rim of a box cut by a sideways cylinder (the cover in patch_trim_thicken_and_stitch), a one-face B-spline sheet: energy 0.7185 → 0.6938 in one step, edges unmoved bit for bit, undo/redo/reopen and the refusals as before. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/surface.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/engine/src/cmd/surface.rs b/crates/engine/src/cmd/surface.rs index d7626c7768..7d9235688c 100644 --- a/crates/engine/src/cmd/surface.rs +++ b/crates/engine/src/cmd/surface.rs @@ -1954,17 +1954,25 @@ mod tests { (numbers[0], numbers[1]) } - /// Surface Fair on the fitted B-spline face of an offset sphere: the face is smoothed in - /// place, its edges do not move at all, the reply carries the energy before and after, undo, - /// redo and a cold reopen keep it, and hostile inputs are refused. + /// Surface Fair on the fitted B-spline face of a patch on a rim that is not planar (a box's + /// top cut away by a sideways cylinder): the face is smoothed in place, its edges do not move + /// at all, the reply carries the energy before and after, undo, redo and a cold reopen keep + /// it, and hostile inputs are refused. #[test] fn fairing_a_b_spline_face_keeps_its_edges_and_reports_its_energy() { let mut s = Session::default(); - run(&mut s, "solid.sphere", json!({"radius": 20, "body_name": "Ball"})); - // A sphere is neither a plane nor a cylinder, so its offset is a fitted B-spline face. - run(&mut s, "surface.offset", json!({"faces": [[0, 0, 20]], "body": "Ball", "distance": 2, "body_name": "Shell"})); + run(&mut s, "solid.box", json!({"length": 28, "width": 28, "height": 20, "corner": [-14, -14, 0], "body_name": "Saddle"})); + run( + &mut s, + "solid.cylinder", + json!({"radius": 40, "height": 120, "base": [0, -60, 50], "axis": "Y", "operation": "cut", "targets": ["Saddle"]}), + ); + let z = |x: f64| 50.0 - (1600.0 - x * x).sqrt(); + let rim = json!([[14, 0, z(14.0)], [0, 14, z(0.0)], [-14, 0, z(-14.0)], [0, -14, z(0.0)]]); + // The rim is not planar, so its patch is a fitted B-spline face. + run(&mut s, "surface.patch", json!({"edges": rim, "body": "Saddle", "body_name": "Shell"})); let st = s.world_state().unwrap(); - assert!(st.body("Shell").unwrap().body.is_surface(), "an offset sphere face is a sheet"); + assert!(st.body("Shell").unwrap().body.is_surface(), "a patch on a rim is a sheet"); let before: Vec = st.body("Shell").unwrap().body.edges(0.1).unwrap().iter().flat_map(|e| e.points.clone()).collect(); assert!(!before.is_empty()); let area_before = area(&s, "Shell");