Cuts leave the bodies their tools can't reach, by exact boxes (#10225 on exact geometry)

- The per-target cut loop skips a body whose exact box lies clear of
  every tool's, as main's version did with mesh boxes. The sheet culls
  (#10226, #10301) and this one now leave the far sheets and bodies alone:
  a_cut_leaves_bodies_it_cannot_reach_as_they_were passes and leaves the
  known-failing list.
- a_cut_still_runs_where_its_tool_touches_grazes_or_meets_a_curved_face:
  a tool 0.5 µm clear of the block is now left out (exact boxes; 0.5 µm is
  far past the bodies' tolerances); touching and 0.1 mm in still cut.
- Known failing, with reasons: main's edge lookup by a stored point
  (#11286, on the display mesh) is not taken; SMLib refuses the
  wrong-way chamfer for its tangent chain first.
- EXEMPT: main's eight new sketch-only commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M41G8Nua7HvuFPZkmJ
This commit is contained in:
jyviko
2026-11-02 17:25:13 -05:00
parent e6a4b0a9ae
commit 5acbd2e714
4 changed files with 34 additions and 9 deletions
+14
View File
@@ -3094,10 +3094,24 @@ fn apply_traced_with(
let affected: std::collections::BTreeMap<String, usize> =
target_idx.iter().filter_map(|i| state.bodies.get(*i)).map(|b| (b.name.clone(), b.body.lumps().map_or(1, |l| l.len()))).collect();
let mut remove = Vec::new();
// A cut hands a body its tools cannot reach back as it was, but only after a whole
// boolean: in a design of many bodies that was most of a hole's time (#10225). A body
// whose exact box lies clear of every tool's is left as it is. A body shown in another
// frame, and a mesh body, are cut as before; an intersect removes the bodies it misses.
let reach: Option<Vec<Option<solidcraft_geom::Aabb3>>> =
(op == Operation::Cut && !tools.iter().any(|t| t.body.is_mesh())).then(|| tools.iter().map(|t| more::exact_box(&t.body)).collect());
for &ti in &target_idx {
let Some(mut acc) = state.bodies.get(ti).map(|b| Some(b.traced())) else { continue };
// The tools meet the target where it is shown: in its frame (#3383).
let into = state.bodies.get(ti).and_then(|b| tool_frame(&b.name));
if let (Some(reach), None, Some(mb)) = (&reach, into, state.bodies.get(ti))
&& !reach.is_empty()
&& !mb.body.is_mesh()
&& let Some(target) = more::exact_box(&mb.body)
&& reach.iter().all(|tool| more::boxes_apart(&Some(target), tool))
{
continue;
}
#[cfg(test)]
cost_tests::count(|c| c.cut += 1);
for t in &tools {
+8 -6
View File
@@ -1182,17 +1182,19 @@ fn a_cut_leaves_bodies_it_cannot_reach_as_they_were() {
assert!(volume(&work.model, "Near") < 60_000.0 - 800.0, "and it is cut");
}
/// A cut still goes through the boolean wherever its tool reaches a body or comes close: on a
/// face, along a line, a hair beside it, into a dome above its edge circle. (Bodies its tool
/// cannot reach are left out of it: `a_cut_leaves_bodies_it_cannot_reach_as_they_were`.)
/// A cut still goes through the boolean wherever its tool reaches a body: on a face, along a
/// line, into a dome above its edge circle. The boxes are exact, so a tool clear of a body by
/// more than their tolerances leaves it out. (Bodies its tool cannot reach are left out of it:
/// `a_cut_leaves_bodies_it_cannot_reach_as_they_were`.)
#[test]
fn a_cut_still_runs_where_its_tool_touches_grazes_or_meets_a_curved_face() {
// A cylinder whose side is tangent to the face x = 50, one a hair clear of it, one 0.1 mm in.
for (x, cuts) in [(53.0, false), (53.0005, false), (52.9, true)] {
// A cylinder whose side is tangent to the face x = 50, one 0.5 µm clear of it (far past the
// bodies' tolerances, so left out), one 0.1 mm in.
for (x, cuts, boolean) in [(53.0, false, 1), (53.0005, false, 0), (52.9, true, 1)] {
let mut doc = Document::new("graze");
block(&mut doc, "A", Vec3::ZERO, [50.0, 40.0, 30.0]);
let work = cut_work(&mut doc, cutter(Vec3::new(x, 20.0, 0.0), 3.0, 30.0));
assert_eq!(work.cut, 1, "the tool at x = {x} goes through the boolean");
assert_eq!(work.cut, boolean, "the tool at x = {x} goes through the boolean {boolean} time(s)");
let v = volume(&work.model, "A");
assert_eq!(v < 60_000.0 - 1.0, cuts, "the tool at x = {x} cuts material: {v}");
assert!(!cuts || work.kept.is_empty(), "a body cut is a new body");
+4 -3
View File
@@ -11,12 +11,12 @@
solidcraft-cli::action_matrix::action_matrix_sample 2 baseline actions fail on SMLib: 2 shells (Bad Loop Orient on issue-616-lid-ribs; status 1001 on filleted-shelled-box, shelled again open at an inner wall)
solidcraft-cli::naming_corpus::corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone oracle/83-boundary-loop-thicken does not load: step 8, SMLib thicken status 1001
solidcraft-doc::eval::chain_tests::a_propagated_chain_that_cannot_build_says_how_to_blend_the_edge_alone the propagated chain now builds a round (9 faces), so there is no refusal to read, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-doc::eval::cost_tests::a_cut_leaves_bodies_it_cannot_reach_as_they_were main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_searches_only_the_bodies_near_it main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_still_searches_the_bodies_within_its_reach main's mesh-based version (#10303) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_searches_only_the_bodies_near_it main's mesh-based tap-marking cull (#10303, beyond_cylinder_reach) not taken; the exact replacement is to come
solidcraft-doc::eval::cost_tests::a_tap_marking_still_searches_the_bodies_within_its_reach main's mesh-based tap-marking cull (#10303, beyond_cylinder_reach) not taken; the exact replacement is to come
solidcraft-engine::cmd::file::tests::each_format_has_an_export_command_of_its_own SMLib meshes a box's planar faces into 124 triangles, not 12 (the STL is 6284 bytes, the test counts 84 + 50 x 12)
solidcraft-engine::cmd::sketch_project::tests::intersection_curve_of_picked_faces_spans_the_whole_surface main's mesh-based version (#9107) not taken; the exact replacement is to come
solidcraft-engine::extent_tests::cut_to_the_far_side_of_a_curved_wall main's mesh-based version (#8634) not taken; the exact replacement is to come
solidcraft-engine::face_name_tests::a_join_that_makes_the_body_bigger_leaves_round_walls_it_never_touched_alone main's edge lookup by a stored point (#11286) finds the edge on the display mesh (edge_near on the body's mesh), not taken; the exact replacement is to come
solidcraft-engine::hole_face_tests::a_hole_wider_than_the_part_says_it_removes_all_of_it a 40 mm hole at (10, 10) touches the plate's edge y = 30 at one point; SMLib parts the plate there into 2 bodies, the test wants truck's 1
solidcraft-engine::measure_centre_tests::a_fillet_round_a_boss_reports_its_radius SMLib's round at the foot of a boss is not an analytic torus of minor radius 3, so no face of the body is (the test finds none to measure)
solidcraft-engine::tests::fillet_fit_taper_closes_to_a_point SMLib fillet status 1001 on the taper fit (radius 16 closing to 0)
@@ -27,6 +27,7 @@ solidcraft-kernel::blend::corner_tests::corner_blends_hold_at_any_scale at 0.01x
solidcraft-kernel::blend_corner::tests::a_round_next_to_a_round_of_another_radius the face count is 9, not the expected count, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::blend_corner::tests::issue2422_vertical_after_separate_bottom_rounds SMLib's check refuses the fillet: edge and vertex tolerance 0.97 against the body's 0.01 (#2422)
solidcraft-kernel::blend_smlib::tests::smooth_edges_and_unfinished_tangent_chains_are_refused_saying_why the smooth edge builds (volume 7957.723) where a refusal is expected, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::blend_wrong_way_tests::a_chamfer_that_would_grow_the_part_on_a_convex_edge_is_refused SMLib refuses the chamfer for another reason first: status 1001, the picked edge runs on tangentially into an unblended edge (tangent_chain is on)
solidcraft-kernel::corner_g2::tests::a_concave_corner_takes_the_g2_patch_too the concave G2 corner's curvature jump clear of the corners is 5.5e-2, above the bound, on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
solidcraft-kernel::corner_g2::tests::a_long_setback_keeps_the_g2_patch_inside_the_box at set backs 11 to 15 the G2 corner patch bulges 2.6e-6 to 1.33e-3 past the box (the explicit corner is in progress)
solidcraft-kernel::corner_g2::tests::curvature_rounds_meet_at_a_g2_corner the corner loop's fill misses its neighbours' curvature by 1.6e-3 (tolerance 1e-3), on SMLib v1.1.0-alpha (a18bbe5), passed on f916a8d; cause being established
+8
View File
@@ -181,7 +181,14 @@ sketch.constraint.polygon 2D sketch only (the sketch solver and engine t
sketch.constraint.symmetry 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.angle 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.bisector 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.horizontal 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.parallel 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.perpendicular 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.tangent_at 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.tangent_external 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.tangent_two 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.construction_line.vertical 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.copy 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.cut 2D sketch only (the sketch solver and engine tests); no kernel operation
@@ -192,6 +199,7 @@ sketch.drag_end 2D sketch only (the sketch solver and engine t
sketch.draw.dimensioned 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.drawing_bounds 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.edit_text 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.equation_curve 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.export_dxf 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.extend 2D sketch only (the sketch solver and engine tests); no kernel operation
sketch.fillet 2D sketch only (the sketch solver and engine tests); no kernel operation