Files
solidcraft-upstream/crates/doc/src/feature_geometry.rs
T
JIJINBEIandjijinbei 464a6dfad4 Feature walks: generate them from field roles with #[derive(Walk)] (#1251)
The three walks over a feature (expressions, references, geometry) are generated from FeatureKind by #[derive(Walk)] in a new proc-macro crate, solidcraft-derive, from #[walk(...)] attributes written next to each field. The hand-written walks in params.rs, feature_refs.rs and feature_geometry.rs are gone; Ruled Surface and Extend have their attributes, and the three golden walk records are unchanged.

Co-authored-by: jijinbei <[email protected]>
2026-10-15 00:13:53 -04:00

102 lines
3.5 KiB
Rust

//! The geometry a feature holds, each piece with its role: the points that pick faces (moved
//! with the feature, and the source of its persistent face names), other positions, directions,
//! planes, construction references, a primitive's placement point and its profile selections.
//! The walk (`crate::walk`) is behind `transform_geometry`, `face_points`, `profile_sels` and
//! `point_expr`.
use solidcraft_geom::Vec3;
use crate::walk::Walk;
use crate::{FeatureKind, PointExpr, ProfileSel};
/// A piece of a feature's geometry: `V` is `&Vec3` or `&mut Vec3`, and so on for the others.
pub(crate) enum Geo<V, P, G, E, S> {
/// A point that picks a face: it moves with the feature and names the face it picks.
Pick(V),
/// A point that picks a face but stays where it is when the feature is moved (an Emboss
/// cylinder, chosen in its component's frame).
Pinned(V),
/// Any other position (an edge pick, an axis origin, a fold line): it moves with the feature.
Pos(V),
/// A direction: it turns with the feature.
Dir(V),
Plane(P),
/// A construction axis's or point's reference to the model.
Construct(G),
/// A primitive's placement point (length expressions).
Placement(E),
/// A profile selection, with its sketch.
Profiles(u64, S),
}
impl FeatureKind {
/// The points that pick faces (shell, draft, offset and replace faces, a hole's placement and
/// `to`, an extrude's `to` and `from`…), in the order of the feature's persistent face names.
pub fn face_points_mut(&mut self) -> Vec<&mut Vec3> {
let mut v = Vec::new();
self.walk_geometry_mut(&mut |g| {
if let Geo::Pick(p) | Geo::Pinned(p) = g {
v.push(p);
}
});
v
}
/// Read-only view of [`FeatureKind::face_points_mut`].
pub fn face_points(&self) -> Vec<Vec3> {
let mut v = Vec::new();
self.walk_geometry(&mut |g| {
if let Geo::Pick(p) | Geo::Pinned(p) = g {
v.push(*p);
}
});
v
}
/// The feature's profile selections, each with its sketch.
pub fn profile_sels_mut(&mut self) -> Vec<(u64, &mut ProfileSel)> {
let mut v = Vec::new();
self.walk_geometry_mut(&mut |g| {
if let Geo::Profiles(sketch, sel) = g {
v.push((sketch, sel));
}
});
v
}
/// Read-only view of [`FeatureKind::profile_sels_mut`].
pub fn profile_sels(&self) -> Vec<(u64, &ProfileSel)> {
let mut v = Vec::new();
self.walk_geometry(&mut |g| {
if let Geo::Profiles(sketch, sel) = g {
v.push((sketch, sel));
}
});
v
}
/// A primitive's placement point (length expressions). Its coordinates are not inputs:
/// they get no parameter names and keep bare numbers in mm whatever the design's units, as
/// every other position does; renames and users still find them.
pub fn point_expr_mut(&mut self) -> Option<&mut PointExpr> {
let mut found = None;
self.walk_geometry_mut(&mut |g| {
if let Geo::Placement(p) = g {
found = Some(p);
}
});
found
}
/// Read-only view of [`FeatureKind::point_expr_mut`].
pub fn point_expr(&self) -> Option<&PointExpr> {
let mut found = None;
self.walk_geometry(&mut |g| {
if let Geo::Placement(p) = g {
found = Some(p);
}
});
found
}
}