Refuse fillets and chamfers that run past their faces or cross each other (#1080) (#1124)

* Refuse fillets and chamfers that run past their faces or cross each other (#1080)

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Blend fit: chamfers keep their old acceptance of crossed loops; skip the volume bound along tangent chains

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Blend fit: one selection per check, a coarse volume pass first; record the refused oversize blends in the action matrix baseline

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-14 11:46:44 -04:00
1 parent 6df69e9def
commit 563bcaff5b
8 files changed
+679 -46

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
//! #1080: a fillet or chamfer too large for the geometry beside its edge is refused, naming the
//! largest size that fits, and one that fits still builds.
use std::path::Path;
use serde_json::json;
use super::{run, volume};
use crate::Session;
fn open_fixture() -> Session {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("src/tests/fixtures/cubeish-chamfer-too-large.solidcraft");
let mut s = Session::default();
run(&mut s, "doc.open", json!({"path": path.to_string_lossy()}));
s
}
fn chamfer_error(s: &Session) -> Option<String> {
s.model.results.iter().find(|r| r.name == "Chamfer1").and_then(|r| r.error.clone())
}
/// The report's design: a 20 mm cube with a 10 mm square opening into each of three faces,
/// then a 9 mm chamfer on the top edge over one side opening. The openings are 5 mm from the
/// edge, so the chamfer would cut through their rims. It is refused, naming 5 mm, and the part
/// is left as it was.
#[test]
fn chamfer_through_the_openings_is_refused() {
let mut s = open_fixture();
let err = chamfer_error(&s).expect("the 9 mm chamfer cuts through two openings: it must be refused");
assert!(err.contains("runs past the faces beside the edge"), "{err}");
assert!(err.contains("the largest size that fits is 5 mm"), "{err}");
assert!((volume(&mut s) - 4000.0).abs() < 1e-6, "the part stays as it was without the chamfer");
}
/// Sizes that stop short of the openings build, and take away exactly the chamfer's triangle
/// along the 20 mm edge.
#[test]
fn chamfer_that_fits_still_builds() {
let mut s = open_fixture();
for d in [4.0, 5.0] {
run(&mut s, "timeline.edit", json!({"feature": "Chamfer1", "set": {"distance": format!("{d} mm")}}));
assert_eq!(chamfer_error(&s), None, "{d} mm fits");
let want = 4000.0 - 0.5 * d * d * 20.0;
assert!((volume(&mut s) - want).abs() < 1e-6, "{d} mm: {} (want {want})", volume(&mut s));
}
}