Feature mirrors and patterns: preserve replay and add Flip/Center placement (#1619)

Thanks @Karl-VonRichter.
This commit is contained in:
Karl Von Richter authored and GitHub committed 2026-10-16 03:01:00 -04:00
1 parent f57a62deb7
commit 9422853cf9
11 files changed
+456 -41

No files matched your search

+16
View File
@@ -1721,6 +1721,14 @@ pub enum PatternKind {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(length = "Spacing 2")]
spacing2: Option<Expr>,
#[serde(default, skip_serializing_if = "default_pattern_alignment")]
alignment: solidcraft_sketch::PatternAlignment,
#[serde(default, skip_serializing_if = "default_pattern_alignment")]
alignment2: solidcraft_sketch::PatternAlignment,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
reversed: bool,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
reversed2: bool,
},
Circular {
origin: Position,
@@ -1730,6 +1738,10 @@ pub enum PatternKind {
/// Total angle (360 deg = evenly around).
#[walk(angle = "Total angle")]
angle: Expr,
#[serde(default, skip_serializing_if = "default_pattern_alignment")]
alignment: solidcraft_sketch::PatternAlignment,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
reversed: bool,
},
/// Copies along a chain of sketch curves: instance k moves by path(k·spacing) − path(0),
/// measured along the path from its start.
@@ -1753,6 +1765,10 @@ pub enum PatternKind {
},
}
fn default_pattern_alignment(alignment: &solidcraft_sketch::PatternAlignment) -> bool {
*alignment == solidcraft_sketch::PatternAlignment::Right
}
fn z_axis() -> Dir {
Dir(Vec3::Z)
}
+4 -4
View File
@@ -3561,7 +3561,7 @@ fn pattern_transforms(doc: &Document, vals: &BTreeMap<String, Value>, st: &Model
};
let mut out = Vec::new();
match p {
crate::PatternKind::Rectangular { dir1, count1, spacing1, dir2, count2, spacing2 } => {
crate::PatternKind::Rectangular { dir1, count1, spacing1, dir2, count2, spacing2, alignment, alignment2, reversed, reversed2 } => {
let (n1, s1) = (count(count1)?, val(vals, spacing1, Kind::Length)?);
let d1 = dir1.normalized().ok_or_else(|| DocError::Invalid("pattern direction".into()))?;
let (n2, s2, d2) = match (dir2, count2, spacing2) {
@@ -3578,7 +3578,7 @@ fn pattern_transforms(doc: &Document, vals: &BTreeMap<String, Value>, st: &Model
if i == 0 && j == 0 {
continue;
}
out.push(translation(d1 * (s1 * i as f64) + d2 * (s2 * j as f64)));
out.push(translation(d1 * (s1 * alignment.multiplier(i, *reversed)) + d2 * (s2 * alignment2.multiplier(j, *reversed2))));
}
}
}
@@ -3615,7 +3615,7 @@ fn pattern_transforms(doc: &Document, vals: &BTreeMap<String, Value>, st: &Model
out.push(m);
}
}
crate::PatternKind::Circular { origin, axis, count: c, angle } => {
crate::PatternKind::Circular { origin, axis, count: c, angle, alignment, reversed } => {
let n = count(c)?;
let total = val(vals, angle, Kind::Angle)?;
let full = (total.abs() - std::f64::consts::TAU).abs() < 1e-9;
@@ -3627,7 +3627,7 @@ fn pattern_transforms(doc: &Document, vals: &BTreeMap<String, Value>, st: &Model
0.0
};
for i in 1..n {
out.push(rotation(origin.0, axis.0, step * i as f64));
out.push(rotation(origin.0, axis.0, step * alignment.multiplier(i, *reversed)));
}
}
}
@@ -0,0 +1,4 @@
//! Rectangular and circular feature patterns store alignment and reversal, independently for
//! each rectangular direction. Defaults preserve older positive-direction placements.
//! Center retains the source and alternates copies on either side, as sketch patterns do.
//! The last release refuses this pending format and asks for an update instead of losing it.
+1
View File
@@ -42,6 +42,7 @@ impl Walk for i8 {}
impl Walk for f64 {}
impl Walk for ProfileSel {}
impl Walk for solidcraft_sketch::Sketch {}
impl Walk for solidcraft_sketch::PatternAlignment {}
impl Walk for solidcraft_kernel::StepNode {}
impl Walk for crate::document::Operation {}
impl Walk for solidcraft_kernel::Continuity {}