Sweep: orientation, twist and end scale (#1269)

Part of #771 and #772. solid.sweep and surface.sweep take orientation (perpendicular, parallel or a direction), twist (up to 4 turns) and end scale (0.01 to 100), applied about the profile's normal through the path's start; default options run the old sweep, so existing sweeps are unchanged. New fields are optional, left out when unset and noted under format 21; twist and scale are model parameters. Both sweep dialogs get Orientation, Twist and End Scale rows; labels in every catalog. Checked on main + this branch: cargo check --workspace, kernel/engine/UI sweep tests, the doc suite and the robustness goldens.
This commit is contained in:
Irakli Kourtis authored and GitHub committed 2026-10-15 06:24:31 -04:00
1 parent 0872eb959a
commit 5fa8e7d60a
30 files changed
+1120 -71

No files matched your search

+42
View File
@@ -262,6 +262,26 @@ pub struct ThinWall {
pub thickness2: Option<String>,
}
/// How a swept profile turns as it follows its path.
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(rename_all = "snake_case")]
pub enum SweepOrientation {
/// Square to the path, turning with it (a rotation-minimising frame).
#[default]
Perpendicular,
/// As drawn: the profile moves along the path without turning.
Parallel,
/// Square to the path, its turn about the path fixed by this direction (in the feature's
/// frame): the direction's projection onto the profile stays where it was at the start.
Direction(#[walk(dir)] Vec3),
}
impl SweepOrientation {
pub fn is_perpendicular(&self) -> bool {
*self == SweepOrientation::Perpendicular
}
}
/// Where a thin wall lies against its curves. A closed loop's inside is the area it encloses;
/// an open chain's is the side it bends toward (a straight one's, the left of its first
/// curve as drawn).
@@ -701,6 +721,17 @@ pub enum FeatureKind {
#[walk(sketch)]
path_sketch: u64,
path: Vec<String>,
/// How the profile turns along the path (default: perpendicular to it).
#[serde(default, skip_serializing_if = "SweepOrientation::is_perpendicular")]
orientation: SweepOrientation,
/// Angle the profile turns about the path over its length.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(angle = "Twist")]
twist: Option<String>,
/// The profile's scale at the end of the path (linear along its length).
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(unitless = "Scale")]
scale: Option<String>,
#[serde(default)]
operation: Operation,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
@@ -1327,6 +1358,17 @@ pub enum FeatureKind {
#[walk(sketch)]
path_sketch: u64,
path: Vec<String>,
/// How the profile turns along the path (default: perpendicular to it).
#[serde(default, skip_serializing_if = "SweepOrientation::is_perpendicular")]
orientation: SweepOrientation,
/// Angle the profile turns about the path over its length.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(angle = "Twist")]
twist: Option<String>,
/// The profile's scale at the end of the path (linear along its length).
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(unitless = "Scale")]
scale: Option<String>,
},
/// A surface body lofted through sections in order, each one open or closed chain of
/// sketch curves: walls only, no caps.