Files
OneCAD/crates/ui-egui/src/sweep_dialog_tests.rs
T
Irakli Kourtis 5fa8e7d60a 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.
2026-10-15 06:24:31 -04:00

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}");
}
}