Kernel: revolved faces turned away from the angle wrap (booleans with revolved bodies work), cuts that leave pieces make separate bodies, trivial booleans (clear of / inside) by sampling, body mirrors with join; recipes: pattern source names, thread, holes at sketch points, mirror of bodies
Oracle: 43/66. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
cb01314d35
commit
57d01f8405
9 files changed
+377
-11
No files matched your search
@@ -215,6 +215,12 @@ pub enum FeatureKind {
|
||||
Mirror {
|
||||
features: Vec<String>,
|
||||
plane: PlaneRef,
|
||||
/// Mirror these bodies instead of replaying features.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
bodies: Vec<String>,
|
||||
/// Join each mirrored body with its original.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
combine: bool,
|
||||
},
|
||||
/// A drilled hole (simple, counterbore or countersink) at a point, into the material.
|
||||
Hole {
|
||||
|
||||
+49
-3
@@ -458,6 +458,20 @@ fn apply_op(state: &mut ModelState, f: &Feature, tools: Vec<Body>, op: Operation
|
||||
i += 1;
|
||||
keep
|
||||
});
|
||||
// A cut can leave a body in pieces: each piece becomes its own body ("Bar", "Bar (1)").
|
||||
let mut split: Vec<ModelBody> = Vec::new();
|
||||
for mb in std::mem::take(&mut state.bodies) {
|
||||
let pieces = mb.body.lumps().unwrap_or_else(|_| vec![mb.body.clone()]);
|
||||
if pieces.len() < 2 {
|
||||
split.push(mb);
|
||||
continue;
|
||||
}
|
||||
for (k, p) in pieces.into_iter().enumerate() {
|
||||
let name = if k == 0 { mb.name.clone() } else { format!("{} ({k})", mb.name) };
|
||||
split.push(ModelBody::new(name, p, mb.feature));
|
||||
}
|
||||
}
|
||||
state.bodies = split;
|
||||
}
|
||||
Operation::NewBody => {}
|
||||
}
|
||||
@@ -1157,7 +1171,13 @@ fn replay(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut
|
||||
return Err(DocError::Invalid("no features selected".into()));
|
||||
}
|
||||
for name in features {
|
||||
let src = doc.find_feature(name).ok_or_else(|| DocError::Unknown(format!("feature `{name}`")))?;
|
||||
// A sketch and its extrude often share a name; the feature that makes geometry wins.
|
||||
let src = doc
|
||||
.features
|
||||
.iter()
|
||||
.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}`")))?;
|
||||
let tools = feature_tools(vals, src, st)?;
|
||||
let (op, targets) = feature_op(src);
|
||||
let mut copies = Vec::new();
|
||||
@@ -1273,9 +1293,35 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
let mats = pattern_transforms(vals, pattern)?;
|
||||
replay(doc, vals, f, st, features, &mats)
|
||||
}
|
||||
FeatureKind::Mirror { features, plane } => {
|
||||
FeatureKind::Mirror { features, plane, bodies, combine } => {
|
||||
let pl = doc.resolve_plane(vals, plane, 0)?;
|
||||
replay(doc, vals, f, st, features, &[mirror_matrix(&pl)])
|
||||
if bodies.is_empty() {
|
||||
return replay(doc, vals, f, st, features, &[mirror_matrix(&pl)]);
|
||||
}
|
||||
let m = mirror_matrix(&pl);
|
||||
for n in bodies {
|
||||
let i = st.bodies.iter().position(|b| &b.name == n).ok_or_else(|| DocError::Unknown(format!("body `{n}`")))?;
|
||||
let Some(mb) = st.bodies.get(i).cloned() else { continue };
|
||||
let mirrored = kernel::transform_matrix(&mb.body, m)?;
|
||||
if *combine {
|
||||
let joined = kernel::boolean(&mb.body, &mirrored, BoolOp::Union)?
|
||||
.ok_or_else(|| DocError::Invalid("the mirror join produced nothing".into()))?;
|
||||
for (k, p) in joined.lumps()?.into_iter().enumerate() {
|
||||
if k == 0 {
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::new(mb.name.clone(), p, mb.feature);
|
||||
}
|
||||
} else {
|
||||
let name = unique_body_name(st, &mb.name);
|
||||
st.bodies.push(ModelBody::new(name, p, f.id));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let name = unique_body_name(st, &mb.name);
|
||||
st.bodies.push(ModelBody::new(name, mirrored, f.id));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::Fillet { edges, radius, body } | FeatureKind::Chamfer { edges, distance: radius, body } => {
|
||||
let r = val(vals, radius, Kind::Length)?;
|
||||
|
||||
Reference in new issue
Block a user