mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-06 20:02:16 +00:00
doc: a pattern or mirror of a pattern or mirror copies what that one made
Replaying a Mirror or Pattern feature asked it for its tools, which only primitives and sketch features have: 'Mirror1 cannot be patterned or mirrored yet' (#3652). A copy of a pattern or mirror of features now replays that feature's own features with its moves followed by these (a mirror of Mirror1 reflects the hole Mirror1 made), nested at most 8 deep, never through itself, and to at most MAX_INSTANCES copies in all. (not built: base in progress) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
@@ -4679,6 +4679,9 @@ fn path_at(segs: &[kernel::PathSeg], d: f64) -> (Vec3, Vec3) {
|
||||
(Vec3::ZERO, Vec3::X)
|
||||
}
|
||||
|
||||
/// Most patterns and mirrors of features nested in one another (a mirror of a mirror).
|
||||
const MAX_REPLAY_DEPTH: usize = 8;
|
||||
|
||||
/// Apply transformed copies of the tools of `features` (patterns, mirrors).
|
||||
fn replay(
|
||||
doc: &Document,
|
||||
@@ -4688,6 +4691,21 @@ fn replay(
|
||||
features: &[String],
|
||||
mats: &[Mat],
|
||||
warning: &mut Option<String>,
|
||||
) -> Result<()> {
|
||||
replay_at(doc, vals, f, st, features, mats, warning, 0)
|
||||
}
|
||||
|
||||
/// [`replay`], `depth` patterns or mirrors of features deep.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn replay_at(
|
||||
doc: &Document,
|
||||
vals: &BTreeMap<String, Value>,
|
||||
f: &Feature,
|
||||
st: &mut ModelState,
|
||||
features: &[String],
|
||||
mats: &[Mat],
|
||||
warning: &mut Option<String>,
|
||||
depth: usize,
|
||||
) -> Result<()> {
|
||||
if features.is_empty() {
|
||||
return Err(DocError::Invalid("no features selected".into()));
|
||||
@@ -4710,6 +4728,29 @@ fn replay(
|
||||
.find(|x| &x.name == name && !matches!(x.kind, FeatureKind::Sketch { .. } | FeatureKind::ConstructionPlane { .. }))
|
||||
.or_else(|| doc.find_feature(name))
|
||||
.ok_or_else(|| DocError::Unknown(format!("feature `{name}`")))?;
|
||||
// A copy of a pattern or mirror of features copies what that one copied: its features,
|
||||
// moved by its moves and then by these.
|
||||
let nested = match &src.kind {
|
||||
FeatureKind::Pattern { features, pattern, bodies } if bodies.is_empty() => {
|
||||
Some((features, pattern_transforms(doc, vals, st, src.component, pattern)?))
|
||||
}
|
||||
FeatureKind::Mirror { features, plane, bodies, .. } if bodies.is_empty() => {
|
||||
Some((features, vec![mirror_matrix(&doc.resolve_plane_in(vals, plane, 0, Some(st))?)]))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some((inner, inner_mats)) = nested {
|
||||
if depth >= MAX_REPLAY_DEPTH || src.id == f.id {
|
||||
return Err(DocError::Invalid(format!("{} copies patterns or mirrors nested too deeply", f.name)));
|
||||
}
|
||||
// As many copies in all as one pattern may make.
|
||||
if mats.len().saturating_mul(inner_mats.len()) > MAX_INSTANCES {
|
||||
return Err(DocError::Invalid(format!("{} would make more than {MAX_INSTANCES} copies", f.name)));
|
||||
}
|
||||
let composed: Vec<Mat> = mats.iter().flat_map(|m| inner_mats.iter().map(move |i| crate::mat_mul(m, i))).collect();
|
||||
replay_at(doc, vals, f, st, &crate::plain(inner), &composed, warning, depth + 1)?;
|
||||
continue;
|
||||
}
|
||||
// A fillet or chamfer repeats at the copied edges.
|
||||
if let FeatureKind::Fillet { edges, radius, .. } | FeatureKind::Chamfer { edges, distance: radius, .. } = &src.kind {
|
||||
let r = val(vals, radius, Kind::Length)?;
|
||||
|
||||
Reference in New Issue
Block a user