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 <jijinbei@users.noreply.github.com>
This commit is contained in:
1 parent
a026a69182
commit
464a6dfad4
13 files changed
+998
-937
No files matched your search
@@ -1,14 +1,13 @@
|
||||
//! 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.
|
||||
//! One walk, written once for `&` and `&mut`, behind `transform_geometry`, `face_points`,
|
||||
//! `profile_sels` and `point_expr`. Every variant is listed, so a new one has to say what each of
|
||||
//! its points is.
|
||||
//! The walk (`crate::walk`) is behind `transform_geometry`, `face_points`, `profile_sels` and
|
||||
//! `point_expr`.
|
||||
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
use crate::construct::GeoRef;
|
||||
use crate::{AxisRef, FeatureKind, PatternKind, PlaneRef, PointExpr, ProfileSel};
|
||||
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> {
|
||||
@@ -30,316 +29,7 @@ pub(crate) enum Geo<V, P, G, E, S> {
|
||||
Profiles(u64, S),
|
||||
}
|
||||
|
||||
pub(crate) type GeoItem<'a> = Geo<&'a Vec3, &'a PlaneRef, &'a GeoRef, &'a PointExpr, &'a ProfileSel>;
|
||||
pub(crate) type GeoItemMut<'a> = Geo<&'a mut Vec3, &'a mut PlaneRef, &'a mut GeoRef, &'a mut PointExpr, &'a mut ProfileSel>;
|
||||
|
||||
/// Every piece of a feature's geometry, written once for `&` and `&mut`: `$item` is `GeoItem` or
|
||||
/// `GeoItemMut`, `$refs` the matching `refs` / `refs_mut`, `$m` is `mut` or nothing. Face picks
|
||||
/// come in the order the feature's face names follow.
|
||||
macro_rules! geometry_walk {
|
||||
($name:ident, $item:ident, $refs:ident $(, $m:tt)?) => {
|
||||
pub(crate) fn $name<'a>(&'a $($m)? self, f: &mut impl FnMut($item<'a>)) {
|
||||
use Geo::{Construct, Dir, Pick, Pinned, Placement, Plane, Pos, Profiles};
|
||||
match self {
|
||||
FeatureKind::Sketch { plane, .. } | FeatureKind::ConstructionPlane { plane } | FeatureKind::Mirror { plane, .. } => f(Plane(plane)),
|
||||
FeatureKind::ConstructionAxis { def } => {
|
||||
for r in def.$refs() {
|
||||
f(Construct(r));
|
||||
}
|
||||
}
|
||||
FeatureKind::ConstructionPoint { def } => {
|
||||
for r in def.$refs() {
|
||||
f(Construct(r));
|
||||
}
|
||||
}
|
||||
FeatureKind::Extrude { sketch, profiles, extent, thin, .. } => {
|
||||
// A thin extrude follows curves; its profiles are not used.
|
||||
if thin.is_none() {
|
||||
f(Profiles(*sketch, profiles));
|
||||
}
|
||||
if let Some(p) = & $($m)? extent.to {
|
||||
f(Pick(p));
|
||||
}
|
||||
if let Some(p) = & $($m)? extent.from {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
// Surface Extrude refuses `to` and `from` for now; they would pick faces as for
|
||||
// Extrude.
|
||||
FeatureKind::SurfaceExtrude { sketch, profiles, extent, .. } => {
|
||||
if let Some(s) = profiles {
|
||||
f(Profiles(*sketch, s));
|
||||
}
|
||||
if let Some(p) = & $($m)? extent.to {
|
||||
f(Pick(p));
|
||||
}
|
||||
if let Some(p) = & $($m)? extent.from {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::Revolve { sketch, profiles, axis, to, .. } => {
|
||||
f(Profiles(*sketch, profiles));
|
||||
if let AxisRef::Line { origin, dir } = axis {
|
||||
f(Pos(origin));
|
||||
f(Dir(dir));
|
||||
}
|
||||
if let Some(p) = to {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceRevolve { sketch, profiles, axis, .. } => {
|
||||
if let Some(s) = profiles {
|
||||
f(Profiles(*sketch, s));
|
||||
}
|
||||
if let AxisRef::Line { origin, dir } = axis {
|
||||
f(Pos(origin));
|
||||
f(Dir(dir));
|
||||
}
|
||||
}
|
||||
FeatureKind::Sweep { sketch, profiles, .. } | FeatureKind::SheetBase { sketch, profiles, .. } => f(Profiles(*sketch, profiles)),
|
||||
FeatureKind::SurfaceSweep { sketch, profiles, .. } => {
|
||||
if let Some(s) = profiles {
|
||||
f(Profiles(*sketch, s));
|
||||
}
|
||||
}
|
||||
FeatureKind::Emboss { sketch, profiles, face, .. } => {
|
||||
f(Profiles(*sketch, profiles));
|
||||
if let Some(face) = face {
|
||||
f(Pinned(& $($m)? face.at));
|
||||
}
|
||||
}
|
||||
FeatureKind::Loft { sections, .. } => {
|
||||
// A section that is a point has no profile.
|
||||
for s in sections {
|
||||
if s.point.is_none() {
|
||||
f(Profiles(s.sketch, & $($m)? s.profiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceLoft { sections } => {
|
||||
for s in sections {
|
||||
if let Some(p) = & $($m)? s.profiles {
|
||||
f(Profiles(s.sketch, p));
|
||||
}
|
||||
}
|
||||
}
|
||||
FeatureKind::Patch { sketch, profiles, edges, .. } => {
|
||||
if let Some(sketch) = sketch {
|
||||
f(Profiles(*sketch, profiles));
|
||||
}
|
||||
for e in edges {
|
||||
f(Pos(e));
|
||||
}
|
||||
}
|
||||
FeatureKind::Fillet { edges, style, .. } => {
|
||||
for e in edges {
|
||||
f(Pos(e));
|
||||
}
|
||||
if let crate::FilletStyle::Variable { start, .. } | crate::FilletStyle::Spline { start, .. } = style {
|
||||
f(Pos(start));
|
||||
}
|
||||
}
|
||||
FeatureKind::Chamfer { edges, .. } | FeatureKind::SheetHem { edges, .. } => {
|
||||
for e in edges {
|
||||
f(Pos(e));
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceExtend { edges, up_to, .. } => {
|
||||
for e in edges {
|
||||
f(Pos(e));
|
||||
}
|
||||
match up_to {
|
||||
Some(crate::ExtendTo::Plane(plane)) => f(Plane(plane)),
|
||||
Some(crate::ExtendTo::Face(t)) => f(Pos(& $($m)? t.point)),
|
||||
Some(crate::ExtendTo::Bounds) | None => {}
|
||||
}
|
||||
}
|
||||
FeatureKind::Shell { faces, .. }
|
||||
| FeatureKind::OffsetFace { faces, .. }
|
||||
| FeatureKind::DeleteFace { faces, .. }
|
||||
| FeatureKind::SurfaceOffset { faces, .. } => {
|
||||
for p in faces {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceRuled { edges, direction, face, .. } => {
|
||||
for e in edges {
|
||||
f(Pos(e));
|
||||
}
|
||||
if let Some(d) = direction {
|
||||
f(Dir(d));
|
||||
}
|
||||
if let Some(p) = face {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::Unstitch { faces, .. } | FeatureKind::ReverseNormal { faces, .. } => {
|
||||
for p in faces {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
// The face is picked (and named); the holes are picked by points on their edges.
|
||||
FeatureKind::SurfaceUntrim { face, holes, .. } => {
|
||||
f(Pick(& $($m)? face.point));
|
||||
if let Some(points) = holes {
|
||||
for p in points {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
FeatureKind::BoundaryFill { cells, .. } => {
|
||||
for p in cells {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::Draft { faces, neutral, pull, .. } => {
|
||||
for p in faces {
|
||||
f(Pick(p));
|
||||
}
|
||||
f(Plane(neutral));
|
||||
f(Dir(pull));
|
||||
}
|
||||
FeatureKind::ReplaceFace { faces, target, .. } => {
|
||||
for p in faces {
|
||||
f(Pick(p));
|
||||
}
|
||||
f(Plane(target));
|
||||
}
|
||||
FeatureKind::SplitFace { faces, plane, tool, .. } => {
|
||||
for p in faces {
|
||||
f(Pick(p));
|
||||
}
|
||||
f(Plane(plane));
|
||||
if let Some(t) = tool {
|
||||
f(Pos(& $($m)? t.point));
|
||||
}
|
||||
}
|
||||
FeatureKind::Split { plane, tool, .. } => {
|
||||
f(Plane(plane));
|
||||
if let Some(t) = tool {
|
||||
f(Pos(& $($m)? t.point));
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceTrim { plane, tool, keep, .. } => {
|
||||
f(Plane(plane));
|
||||
if let Some(t) = tool {
|
||||
f(Pos(& $($m)? t.point));
|
||||
}
|
||||
f(Pos(keep));
|
||||
}
|
||||
FeatureKind::Box { corner: p, .. } | FeatureKind::Sphere { center: p, .. } | FeatureKind::Torus { center: p, .. } => {
|
||||
f(Placement(p))
|
||||
}
|
||||
FeatureKind::Cylinder { base, axis, .. } | FeatureKind::Coil { base, axis, .. } => {
|
||||
f(Placement(base));
|
||||
f(Dir(axis));
|
||||
}
|
||||
FeatureKind::Pattern { pattern, .. } => match pattern {
|
||||
PatternKind::Rectangular { dir1, dir2, .. } => {
|
||||
f(Dir(dir1));
|
||||
if let Some(d) = dir2 {
|
||||
f(Dir(d));
|
||||
}
|
||||
}
|
||||
PatternKind::Circular { origin, axis, .. } => {
|
||||
f(Pos(origin));
|
||||
f(Dir(axis));
|
||||
}
|
||||
// Follows its path sketch.
|
||||
PatternKind::Path { .. } => {}
|
||||
},
|
||||
FeatureKind::Hole { position, direction, points, to, .. } => {
|
||||
// Placed at sketch points, the hole names no face by its position.
|
||||
if points.is_none() {
|
||||
f(Pick(position));
|
||||
} else {
|
||||
f(Pos(position));
|
||||
}
|
||||
f(Dir(direction));
|
||||
if let Some(p) = to {
|
||||
f(Pick(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::Thread { face, .. } => f(Pick(face)),
|
||||
FeatureKind::SheetFlange { edges, .. } => {
|
||||
for e in edges {
|
||||
f(Pos(& $($m)? e.point));
|
||||
}
|
||||
}
|
||||
FeatureKind::SheetFold { a, b, fixed, .. } => {
|
||||
f(Pos(a));
|
||||
f(Pos(b));
|
||||
if let Some(p) = fixed {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::SheetConvert { face, bends, .. } => {
|
||||
// With bend edges the fixed face is found by name (a plate keeps its point).
|
||||
if bends.is_empty() {
|
||||
f(Pos(face));
|
||||
} else {
|
||||
f(Pick(face));
|
||||
}
|
||||
for p in bends {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
FeatureKind::Boss { position, direction, .. } => {
|
||||
f(Pick(position));
|
||||
f(Dir(direction));
|
||||
}
|
||||
FeatureKind::SnapFit { position, direction, hook, .. } => {
|
||||
f(Pick(position));
|
||||
f(Dir(direction));
|
||||
f(Dir(hook));
|
||||
}
|
||||
FeatureKind::Rest { position, direction, along, .. } => {
|
||||
f(Pick(position));
|
||||
f(Dir(direction));
|
||||
if let Some(a) = along {
|
||||
f(Dir(a));
|
||||
}
|
||||
}
|
||||
FeatureKind::Lip { face, .. } => f(Pos(face)),
|
||||
FeatureKind::Align { from, to, from_normal, to_normal, .. } => {
|
||||
f(Pos(from));
|
||||
f(Pos(to));
|
||||
if let Some(n) = from_normal {
|
||||
f(Dir(n));
|
||||
}
|
||||
if let Some(n) = to_normal {
|
||||
f(Dir(n));
|
||||
}
|
||||
}
|
||||
FeatureKind::Scale { origin, .. } => f(Pos(origin)),
|
||||
FeatureKind::Move { rotate_axis, .. } => {
|
||||
if let Some(a) = rotate_axis {
|
||||
f(Dir(a));
|
||||
}
|
||||
}
|
||||
FeatureKind::SheetContour { .. }
|
||||
| FeatureKind::SheetPerforate { .. }
|
||||
| FeatureKind::SheetUnfold { .. }
|
||||
| FeatureKind::Combine { .. }
|
||||
| FeatureKind::BoundingSolid { .. }
|
||||
| FeatureKind::Pipe { .. }
|
||||
| FeatureKind::Rib { .. }
|
||||
| FeatureKind::Remove { .. }
|
||||
| FeatureKind::Stitch { .. }
|
||||
| FeatureKind::Thicken { .. }
|
||||
| FeatureKind::Import { .. }
|
||||
| FeatureKind::MeshImport { .. }
|
||||
| FeatureKind::MeshConvert { .. }
|
||||
| FeatureKind::BodyTransfer { .. } => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl FeatureKind {
|
||||
geometry_walk!(walk_geometry, GeoItem, refs);
|
||||
geometry_walk!(walk_geometry_mut, GeoItemMut, refs_mut, mut);
|
||||
|
||||
/// 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> {
|
||||
|
||||
Reference in new issue
Block a user