Sketch on cut walls, chamfers, pattern copies, join-merged sides and split faces (#625)

A flat face that no construction certificate names on its own now attaches by its exact history name (a new lineage face certificate): cut walls and floors, chamfer faces, each pattern or mirror copy, side walls a Join merged, and the pieces a later feature split a face into. Construction certificates still come first; a seed keeps its certificate when it is patterned. Two flush extrudes of one outline joined end to end keep their exact history in the prism boolean. Face sketch 52% -> 71%, offset plane 52% -> 71%, press-pull/extrude from face 41% -> 60% in the action matrix; baseline blessed.

Fixes #491, fixes #492, fixes #493, fixes #557.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-13 05:26:29 -04:00
1 parent 27f20f97cb
commit 6d5df4b9b3
18 files changed
+786 -381

No files matched your search

+27 -16
View File
@@ -136,31 +136,42 @@ fn generated_profiles_and_press_pull_convert_rotated_occurrence_picks_once() {
}
}
/// A 40 x 30 x 20 box whose top is split at x = 20 and its left half raised 5 by Offset Face:
/// the raised top has no construction certificate and no exact history name yet (#494).
fn raised_half(s: &mut Session, body: &str) {
run(s, "solid.box", json!({"length":40,"width":30,"height":20,"body_name":body}));
run(s, "solid.split_face", json!({"faces":[[10,15,20]],"plane":{"origin":[20,0,0],"normal":[1,0,0]}}));
run(s, "solid.offset_face", json!({"faces":[[10,15,20]],"distance":5}));
}
#[test]
fn legacy_internal_capture_refuses_an_uncaptured_source_in_another_component() {
let mut s = Session::default();
let component = run(&mut s, "component.create", json!({"name":"Source"}));
let occurrence = component["occurrence"].as_u64().unwrap();
run(&mut s, "solid.box", json!({"length":40,"width":30,"height":20,"body_name":"Stock"}));
// A top merged from two joined boxes has no single certified source: the legacy path.
run(&mut s, "solid.box", json!({"length":40,"width":30,"height":20,"corner":[40,0,0],"operation":"join"}));
// A face Offset Face raised has no construction certificate or exact history name yet:
// the legacy path.
raised_half(&mut s, "Stock");
run(&mut s, "component.activate", json!({"component":0}));
run(&mut s, "occurrence.move", json!({"occurrence":occurrence,"translate":[30,0,0],"capture":false}));
let state = s.model.state();
let index = state
// The raised half's top.
let end = state
.body("Stock")
.unwrap()
.body
.faces(1e-4)
.unwrap()
.iter()
.find(|face| face.plane_normal.is_some_and(|normal| normal.z > 0.999) && (face.centroid.z - 20.0).abs() < 1e-6)
.unwrap()
.index;
.into_iter()
.find(|face| face.plane_normal.is_some_and(|normal| normal.z > 0.999) && (face.centroid.z - 25.0).abs() < 1e-6)
.unwrap();
let before = s.doc.to_json();
let error =
super::super::sketch::face::capture_internal(&s, &json!({"face":[35,5,20],"body":"Stock","index":index,"path":[occurrence]}), "internal")
.unwrap_err();
let error = super::super::sketch::face::capture_internal(
&s,
&json!({"face":[40,15,25],"body":"Stock","index":end.index,"path":[occurrence]}),
"internal",
)
.unwrap_err();
assert!(error.to_string().contains("capture the source occurrence position"), "{error}");
assert_eq!(s.doc.to_json(), before);
}
@@ -278,14 +289,14 @@ fn join_keeps_exact_face_attachments_from_both_operands() {
}
#[test]
fn join_leaves_a_face_merged_from_both_operands_without_an_attachment() {
fn join_gives_a_face_merged_from_both_operands_its_history_name() {
let mut s = Session::default();
run(&mut s, "solid.box", json!({"length":20,"width":20,"height":10}));
run(&mut s, "solid.box", json!({"length":20,"width":20,"height":10,"corner":[20,0,0],"operation":"join"}));
// Both boxes' tops share one support: no single construction identity owns it.
let error = s.execute("sketch.create", &json!({"plane":{"face":[10,10,10]}})).unwrap_err().to_string();
assert!(error.contains("fixed:true"), "{error}");
run(&mut s, "sketch.create", json!({"plane":{"face":[10,10,10],"fixed":true}}));
// Both boxes' tops share one support: no single construction certificate owns it, but its
// exact history names it (#491).
let top = run(&mut s, "sketch.create", json!({"plane":{"face":[10,10,10]}}))["sketch"].as_u64().unwrap();
assert_eq!(face_anchor(&s, top).target.certificate, Some(solidcraft_doc::config::FaceCertificate::Lineage));
// An unshared support keeps its box role.
run(&mut s, "sketch.finish", json!({}));
let side = run(&mut s, "sketch.create", json!({"plane":{"face":[0,10,5]}}))["sketch"].as_u64().unwrap();