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.
102 lines
4.6 KiB
Rust
102 lines
4.6 KiB
Rust
//! The Sweep and Surface Sweep dialogs' options (#771): orientation, twist and end scale reach
|
|
//! the commands, and editing a sweep keeps them.
|
|
use crate::dialogs::Kind;
|
|
use crate::dialogs_surface::Surf;
|
|
use crate::scenario::Harness;
|
|
use serde_json::json;
|
|
use solidcraft_engine::Sel;
|
|
use solidcraft_engine::doc::{FeatureKind, SweepOrientation};
|
|
use solidcraft_engine::geom::Vec3;
|
|
|
|
/// A square `Q` on XY and a path `P` 40 up the Z axis; the square's sketch id.
|
|
fn setup(h: &mut Harness) -> u64 {
|
|
h.app.run("sketch.create", json!({"plane":"XY","name":"Q"})).unwrap();
|
|
h.app.run("sketch.rectangle.two_point", json!({"p0":[-5,-5],"p1":[5,5]})).unwrap();
|
|
h.app.run("sketch.finish", json!({})).unwrap();
|
|
h.app.run("sketch.create", json!({"plane":"XZ","name":"P"})).unwrap();
|
|
h.app.run("sketch.line", json!({"points":[[0,0],[0,-40]],"ids":["up"]})).unwrap();
|
|
h.app.run("sketch.finish", json!({})).unwrap();
|
|
h.app.session.doc.find_feature("Q").unwrap().id
|
|
}
|
|
|
|
#[test]
|
|
fn a_new_sweep_takes_its_options_from_the_dialog() {
|
|
let mut h = Harness::new();
|
|
let sketch = setup(&mut h);
|
|
h.step(&json!({"call":"ui.start","params":{"command":"solid.sweep"}})).unwrap();
|
|
h.frames(3);
|
|
assert!(h.widget("Twist").is_some() && h.widget("End Scale").is_some() && h.widget("Orientation").is_some());
|
|
let d = h.app.dialog.as_mut().unwrap();
|
|
d.inputs[0].items = vec![Sel::Profile { sketch, index: 0 }];
|
|
d.inputs[1].items = vec![Sel::SketchCurve { id: "up".into() }];
|
|
d.inputs[2].items = vec![Sel::Axis { name: "X".into() }];
|
|
let Kind::Sweep { opts, .. } = &mut d.kind else { panic!("{:?}", d.kind) };
|
|
opts.orientation = 2;
|
|
opts.twist = "90 deg".into();
|
|
opts.scale = "0.5".into();
|
|
h.frames(2);
|
|
h.step(&json!({"widget":"OK"})).unwrap();
|
|
assert!(h.app.dialog.is_none(), "{:?}", h.app.session.log);
|
|
let f = h.app.session.doc.features.last().unwrap();
|
|
let FeatureKind::Sweep { orientation, twist, scale, .. } = &f.kind else { panic!("{:?}", f.kind) };
|
|
assert_eq!(*orientation, SweepOrientation::Direction(Vec3::X));
|
|
assert_eq!(twist.as_deref(), Some("90 deg"));
|
|
assert_eq!(scale.as_deref(), Some("0.5"));
|
|
}
|
|
|
|
#[test]
|
|
fn a_plain_sweep_from_the_dialog_stores_no_options() {
|
|
let mut h = Harness::new();
|
|
let sketch = setup(&mut h);
|
|
h.step(&json!({"call":"ui.start","params":{"command":"solid.sweep"}})).unwrap();
|
|
h.frames(3);
|
|
let d = h.app.dialog.as_mut().unwrap();
|
|
d.inputs[0].items = vec![Sel::Profile { sketch, index: 0 }];
|
|
d.inputs[1].items = vec![Sel::SketchCurve { id: "up".into() }];
|
|
h.step(&json!({"widget":"OK"})).unwrap();
|
|
assert!(h.app.dialog.is_none(), "{:?}", h.app.session.log);
|
|
let f = h.app.session.doc.features.last().unwrap();
|
|
let FeatureKind::Sweep { orientation, twist, scale, .. } = &f.kind else { panic!("{:?}", f.kind) };
|
|
assert!(orientation.is_perpendicular() && twist.is_none() && scale.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn editing_sweeps_keeps_their_options() {
|
|
let mut h = Harness::new();
|
|
setup(&mut h);
|
|
h.app
|
|
.run(
|
|
"solid.sweep",
|
|
json!({"sketch":"Q","path_sketch":"P","path":["up"],"orientation":[1,1,0],"twist":"30 deg","scale":"2","operation":"new","name":"Solid"}),
|
|
)
|
|
.unwrap();
|
|
h.app
|
|
.run(
|
|
"surface.sweep",
|
|
json!({"sketch":"Q","path_sketch":"P","path":["up"],"orientation":"parallel","twist":"45 deg","scale":"0.5","name":"Sheet"}),
|
|
)
|
|
.unwrap();
|
|
h.frames(4);
|
|
for name in ["Solid", "Sheet"] {
|
|
let before = h.app.session.doc.find_feature(name).unwrap().clone();
|
|
h.step(&json!({"call":"ui.editFeature","params":{"feature":name}})).unwrap();
|
|
h.frames(8);
|
|
match &h.app.dialog.as_ref().unwrap().kind {
|
|
Kind::Sweep { opts, .. } | Kind::Surface(Surf::Sweep(opts)) => assert_eq!(opts.twist, if name == "Solid" { "30 deg" } else { "45 deg" }),
|
|
k => panic!("{k:?}"),
|
|
}
|
|
h.step(&json!({"widget":"OK"})).unwrap();
|
|
assert!(h.app.dialog.is_none(), "{:?}", h.app.session.log);
|
|
// The options come back as they were (the profile pick is stored by its curves).
|
|
let options = |k: &FeatureKind| match k {
|
|
FeatureKind::Sweep { orientation, twist, scale, .. } | FeatureKind::SurfaceSweep { orientation, twist, scale, .. } => {
|
|
(*orientation, twist.clone(), scale.clone())
|
|
}
|
|
k => panic!("{k:?}"),
|
|
};
|
|
let after = h.app.session.doc.find_feature(name).unwrap();
|
|
assert_eq!(options(&after.kind), options(&before.kind), "{name}");
|
|
assert_eq!(after.param_names, before.param_names, "{name}");
|
|
}
|
|
}
|