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

+8 -4
View File
@@ -145,6 +145,7 @@ impl Document {
&& self.feature(*sketch).is_some_and(|feature| matches!(&feature.kind, FeatureKind::Sketch { sketch, .. } if sketch.curves.iter().any(|candidate| candidate.id == *curve && !candidate.construction && matches!(candidate.kind, solidcraft_sketch::CurveKind::Line { .. } | solidcraft_sketch::CurveKind::Circle { .. } | solidcraft_sketch::CurveKind::Arc { .. }))))
}
(super::FaceCertificate::Imported { .. }, FeatureKind::Import { .. }) => role.strip_prefix("face:").is_some_and(|index| index.parse::<usize>().is_ok()),
(super::FaceCertificate::Lineage, _) => !role.is_empty(),
(super::FaceCertificate::ShellPlanar { source_producer, source, inner }, FeatureKind::Shell { .. }) => {
*source_producer != target.origin_feature
&& self.flat_certificate_producer_matches(*source_producer, source)
@@ -185,6 +186,9 @@ impl Document {
if body.body.is_mesh() || body.definition_name() != target.body {
return Err(DocError::Invalid("configured face definition does not match".into()));
}
if let Some(super::FaceCertificate::Lineage) = &target.certificate {
return self.lineage_face_indices(body, &target.name);
}
if let Some(super::FaceCertificate::ShellPlanar { source_producer, source, inner }) = &target.certificate {
let indices: Vec<_> = body.body.face_sources().into_iter().flatten().enumerate().filter_map(|(index, current)| {
matches!(current, Some(solidcraft_kernel::FaceSource::ShellPlanar { producer: Some(producer), source: current_source, inner: current_inner, .. }) if *producer == target.origin_feature && inner == current_inner && super::flat_source_matches(source, current_source, *source_producer)).then_some(index)
@@ -238,10 +242,10 @@ impl Document {
matched.then_some(index)
})
.collect();
if indices.len() != 1 {
if indices.is_empty() {
return Err(DocError::Unknown("attached planar face certificate is missing or ambiguous".into()));
}
return Ok(indices);
return self.certified_pieces(body, indices, target.origin_feature);
}
if let Some(super::FaceCertificate::ExtrudeSide { sketch, curve }) = &target.certificate {
let indices: Vec<_> = body.body.face_sources().into_iter().flatten().enumerate().filter_map(|(index, source)| {
@@ -250,7 +254,7 @@ impl Document {
if indices.is_empty() {
return Err(DocError::Unknown("constructed side certificate no longer exists".into()));
}
return Ok(indices);
return Ok(self.without_copies(body, indices));
}
if let Some(super::FaceCertificate::Imported { payload_sha256, item, face }) = &target.certificate {
let indices: Vec<_> = body.body.face_sources().into_iter().flatten().enumerate().filter_map(|(index, source)| {
@@ -259,7 +263,7 @@ impl Document {
if indices.is_empty() {
return Err(DocError::Unknown("immutable import face certificate no longer exists".into()));
}
return Ok(indices);
return Ok(self.without_copies(body, indices));
}
let names = crate::naming::face_names(body);
let indices: Vec<usize> =