Faces split on purpose stay split: the body remembers its Split Face lines, export and healing keep the pieces apart

Split Face records the new edges as polylines on the body (Body::split_lines); the document carries them through later features. STEP export no longer joins pieces of one surface across such a line, and healing (fillets, chamfers, booleans, shell, draft) no longer merges coplanar pieces there, while incidental pieces (boolean leftovers, seam halves) still merge as before. Tests: plane and cylinder splits keep their face count through a STEP round trip (and join without the record), a second split keeps both lines, and an engine test exports a split box after a fillet with 8 faces.

Fixes #11

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-09 21:31:16 +00:00
1 parent 0a1ab40ea0
commit 4c8f080691
12 files changed
+144 -19

No files matched your search

+18
View File
@@ -62,3 +62,21 @@ fn a_tool_that_misses_is_refused() {
assert!(s.execute("solid.split_face", &json!({"faces": [[10, 15, 20]], "plane": {"origin": [100, 0, 0], "normal": [1, 0, 0]}})).is_err());
assert_eq!(s.doc.features.len(), n);
}
#[test]
fn export_keeps_split_faces_through_later_features() {
let mut s = boxed();
run(&mut s, "solid.split_face", json!({"faces": [[10, 15, 20]], "plane": {"origin": [20, 0, 0], "normal": [1, 0, 0]}}));
// A later feature rebuilds the body; the split stays a split in the file.
run(&mut s, "solid.fillet", json!({"edges": [[20, 0, 0]], "radius": 2}));
let (f, _) = faces_volume(&mut s, "B");
assert_eq!(f, 8);
let dir = std::env::temp_dir().join(format!("solvecraft-split-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let step = dir.join("split.step");
run(&mut s, "file.export", json!({"path": step.to_string_lossy()}));
let text = std::fs::read_to_string(&step).unwrap();
let _ = std::fs::remove_dir_all(&dir);
// Six box faces, the top's second piece and the fillet.
assert_eq!(text.matches("ADVANCED_FACE(").count(), 8, "{text}");
}