Feature fields: a type for each role (Expr, BodyName, FacePick…) (#1273)

Thanks @jijinbei.
This commit is contained in:
JIJINBEI authored and GitHub committed 2026-10-16 00:28:12 -04:00
1 parent 3333f8a62b
commit 44968dbfe6
59 files changed
+1505 -1043

No files matched your search

+38 -34
View File
@@ -575,7 +575,7 @@ pub fn commands(app: &SolveApp, k: &Surf, inputs: &[SelInput], extra: &Map<Strin
/// A tool as a selection again: a plane, else the face at the stored point.
fn tool_sel(app: &SolveApp, plane: &PlaneRef, tool: Option<&FaceAt>) -> Option<Sel> {
match tool {
Some(t) => crate::dialogs::face_sel(&app.session, t.point),
Some(t) => crate::dialogs::face_sel(&app.session, t.point.0),
None => crate::dialogs::plane_sel(&app.session, plane),
}
}
@@ -584,7 +584,7 @@ fn tool_sel(app: &SolveApp, plane: &PlaneRef, tool: Option<&FaceAt>) -> Option<S
/// `frame` maps the feature's component frame to the world, for an axis stored as a line.
pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(Kind, Vec<SelInput>, Map<String, Value>)> {
let s = &app.session;
let edge = |p: &Vec3| crate::dialogs::edge_sel(s, *p);
let edge = |p: &solidcraft_engine::doc::Position| crate::dialogs::edge_sel(s, p.0);
let (k, fill): (Surf, Vec<Vec<Sel>>) = match kind {
FeatureKind::SurfaceRevolve { sketch, profiles, curves, axis, angle, angle2, symmetric } => {
let (pick, stored) = match axis {
@@ -594,8 +594,8 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
AxisRef::Line { origin, dir } => (
None,
Some(json!({
"origin": pt(solidcraft_engine::doc::apply_point(frame, *origin)),
"dir": pt(solidcraft_engine::doc::apply_vector(frame, *dir))
"origin": pt(solidcraft_engine::doc::apply_point(frame, origin.0)),
"dir": pt(solidcraft_engine::doc::apply_vector(frame, dir.0))
})),
),
};
@@ -603,9 +603,9 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
if let Some(a2) = angle2 {
extra.insert("angle2".into(), json!(a2));
}
let k = Surf::Revolve { angle: angle.clone(), symmetric: *symmetric, axis: stored };
let k = Surf::Revolve { angle: angle.to_string(), symmetric: *symmetric, axis: stored };
let mut ins = inputs(&k);
for (inp, items) in ins.iter_mut().zip([sheet_sels(app, *sketch, profiles.as_ref(), curves), pick.into_iter().collect()]) {
for (inp, items) in ins.iter_mut().zip([sheet_sels(app, sketch.0, profiles.as_ref(), curves), pick.into_iter().collect()]) {
inp.items = items;
}
return Some((Kind::Surface(k), ins, extra));
@@ -615,23 +615,23 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
(
Surf::Sweep(opts),
vec![
sheet_sels(app, *sketch, profiles.as_ref(), curves),
sheet_sels(app, sketch.0, profiles.as_ref(), curves),
path.iter().map(|id| Sel::SketchCurve { id: id.clone() }).collect(),
direction.into_iter().collect(),
],
)
}
FeatureKind::SurfaceLoft { sections } => {
(Surf::Loft, vec![sections.iter().flat_map(|sec| sheet_sels(app, sec.sketch, sec.profiles.as_ref(), &sec.curves)).collect()])
(Surf::Loft, vec![sections.iter().flat_map(|sec| sheet_sels(app, sec.sketch.0, sec.profiles.as_ref(), &sec.curves)).collect()])
}
FeatureKind::SurfaceExtrude { sketch, profiles, curves, extent } => {
let sels = sheet_sels(app, *sketch, profiles.as_ref(), curves);
let sels = sheet_sels(app, sketch.0, profiles.as_ref(), curves);
let direction = match extent.direction {
Direction::Positive => 0,
Direction::Symmetric => 1,
Direction::Negative => 2,
};
let k = Surf::Extrude { distance: extent.distance.clone(), direction };
let k = Surf::Extrude { distance: extent.distance.to_string(), direction };
let mut ins = inputs(&k);
if let Some(input) = ins.first_mut() {
input.items = sels;
@@ -644,14 +644,14 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
let mut sels: Vec<Sel> = edges.iter().filter_map(edge).collect();
if let Some(sk) = sketch {
let st = s.world_state();
if let Some(ss) = st.sketch(*sk) {
sels.extend((0..ss.profiles.len()).map(|index| Sel::Profile { sketch: *sk, index }));
if let Some(ss) = st.sketch(sk.0) {
sels.extend((0..ss.profiles.len()).map(|index| Sel::Profile { sketch: sk.0, index }));
}
}
let index = PATCH_CONTINUITY.iter().position(|(_, w)| *w == continuity.all.as_str()).unwrap_or(0);
// What the dialog does not show is kept as it was: the crown, edges with a
// continuity of their own, and points that are not on a face any more.
let through: Vec<Sel> = points.iter().filter_map(|p| crate::dialogs::face_sel(s, *p)).collect();
let through: Vec<Sel> = points.iter().filter_map(|p| crate::dialogs::face_sel(s, p.0)).collect();
let mut extra = Map::new();
if *crown != 0.0 {
extra.insert("crown".into(), json!(crown));
@@ -660,7 +660,7 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
extra.insert("continuity".into(), serde_json::to_value(continuity).unwrap_or(Value::Null));
}
if through.len() != points.len() {
extra.insert("points".into(), json!(points.iter().map(|p| pt(*p)).collect::<Vec<_>>()));
extra.insert("points".into(), json!(points.iter().map(|p| pt(p.0)).collect::<Vec<_>>()));
}
let k = Surf::Patch { continuity: index };
let mut ins = inputs(&k);
@@ -669,48 +669,49 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
}
return Some((Kind::Surface(k), ins, extra));
}
FeatureKind::SurfaceOffset { faces, distance, chain, .. } => {
(Surf::Offset { distance: distance.clone(), chain: *chain }, vec![faces.iter().filter_map(|p| crate::dialogs::face_sel(s, *p)).collect()])
}
FeatureKind::SurfaceOffset { faces, distance, chain, .. } => (
Surf::Offset { distance: distance.to_string(), chain: *chain },
vec![faces.iter().filter_map(|p| crate::dialogs::face_sel(s, p.0)).collect()],
),
FeatureKind::SurfaceRuled { edges, distance, mode, angle, direction, flip, corners, face, .. } => {
let k = Surf::Ruled {
distance: distance.clone(),
distance: distance.to_string(),
mode: match mode {
RuledMode::Normal => 0,
RuledMode::Tangent => 1,
RuledMode::Angle => 2,
RuledMode::Direction => 3,
},
angle: angle.clone().unwrap_or_else(|| "5 deg".into()),
angle: angle.as_deref().map(str::to_string).unwrap_or_else(|| "5 deg".into()),
flip: *flip,
round: *corners == RuledCorners::Round,
};
let mut ins = inputs(&k);
let fill = [edges.iter().filter_map(edge).collect(), face.and_then(|p| crate::dialogs::face_sel(s, p)).into_iter().collect()];
let fill = [edges.iter().filter_map(edge).collect(), face.and_then(|p| crate::dialogs::face_sel(s, p.0)).into_iter().collect()];
for (inp, items) in ins.iter_mut().zip(fill) {
inp.items = items;
}
let mut extra = Map::new();
if let Some(d) = direction {
extra.insert("direction".into(), pt(*d));
extra.insert("direction".into(), pt(d.0));
}
return Some((Kind::Surface(k), ins, extra));
}
FeatureKind::Unstitch { body, faces } | FeatureKind::ReverseNormal { body, faces } => {
let sels: Vec<Sel> = if faces.is_empty() {
vec![Sel::Body { name: body.clone() }]
vec![Sel::Body { name: body.to_string() }]
} else {
faces.iter().filter_map(|p| crate::dialogs::face_sel(s, *p)).collect()
faces.iter().filter_map(|p| crate::dialogs::face_sel(s, p.0)).collect()
};
(if matches!(kind, FeatureKind::Unstitch { .. }) { Surf::Unstitch } else { Surf::ReverseNormal }, vec![sels])
}
FeatureKind::Stitch { bodies, tolerance } => (
Surf::Stitch { tolerance: if tolerance.trim() == "0" { String::new() } else { tolerance.clone() } },
vec![bodies.iter().map(|n| Sel::Body { name: n.clone() }).collect()],
Surf::Stitch { tolerance: if tolerance.trim() == "0" { String::new() } else { tolerance.to_string() } },
vec![bodies.iter().map(|n| Sel::Body { name: n.to_string() }).collect()],
),
FeatureKind::Thicken { bodies, thickness, symmetric, operation, .. } => (
Surf::Thicken { thickness: thickness.clone(), symmetric: *symmetric, operation: op_index(operation) },
vec![bodies.iter().map(|n| Sel::Body { name: n.clone() }).collect()],
Surf::Thicken { thickness: thickness.to_string(), symmetric: *symmetric, operation: op_index(operation) },
vec![bodies.iter().map(|n| Sel::Body { name: n.to_string() }).collect()],
),
FeatureKind::SurfaceExtend { edges, distance, mode, up_to, neighbours, .. } => {
// The dialog edits the edges and the distance; the rest is kept as it was.
@@ -726,14 +727,17 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
extra.insert("up_to".into(), json!("bounds"));
}
Some(solidcraft_engine::doc::ExtendTo::Face(t)) => {
extra.insert("up_to".into(), json!({"body": t.body, "point": pt(t.point)}));
extra.insert("up_to".into(), json!({"body": t.body, "point": pt(t.point.0)}));
}
Some(solidcraft_engine::doc::ExtendTo::Plane(PlaneRef::Origin { name } | PlaneRef::Construction { name })) => {
Some(solidcraft_engine::doc::ExtendTo::Plane(PlaneRef::Origin { name })) => {
extra.insert("up_to".into(), json!(name));
}
Some(solidcraft_engine::doc::ExtendTo::Plane(PlaneRef::Construction { name })) => {
extra.insert("up_to".into(), json!(name));
}
_ => {}
}
let k = Surf::Extend { distance: distance.clone() };
let k = Surf::Extend { distance: distance.to_string() };
let mut ins = inputs(&k);
if let Some(inp) = ins.first_mut() {
inp.items = edges.iter().filter_map(edge).collect();
@@ -743,9 +747,9 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
FeatureKind::SurfaceTrim { body, plane, tool, keep } => (
Surf::Trim,
vec![
vec![Sel::Body { name: body.clone() }],
vec![Sel::Body { name: body.to_string() }],
tool_sel(app, plane, tool.as_ref()).into_iter().collect(),
crate::dialogs::face_sel(s, *keep).into_iter().collect(),
crate::dialogs::face_sel(s, keep.0).into_iter().collect(),
],
),
FeatureKind::SurfaceUntrim { face, holes, outer, in_place } => {
@@ -756,12 +760,12 @@ pub fn for_feature(app: &SolveApp, kind: &FeatureKind, frame: &Mat) -> Option<(K
};
(
Surf::Untrim { holes: index, outer: *outer, in_place: *in_place },
vec![crate::dialogs::face_sel(s, face.point).into_iter().collect(), picked],
vec![crate::dialogs::face_sel(s, face.point.0).into_iter().collect(), picked],
)
}
FeatureKind::SplitFace { faces, plane, tool, .. } => (
Surf::SplitFace,
vec![faces.iter().filter_map(|p| crate::dialogs::face_sel(s, *p)).collect(), tool_sel(app, plane, tool.as_ref()).into_iter().collect()],
vec![faces.iter().filter_map(|p| crate::dialogs::face_sel(s, p.0)).collect(), tool_sel(app, plane, tool.as_ref()).into_iter().collect()],
),
_ => return None,
};