Sketch Slice: cut at the sketch plane while a Section Analysis is on (#10705) (#10768)

With a section on, Slice in the Sketch Palette lit up but the model was
still cut only by the section: the viewport took the sketch's plane only
when there was no section. Slice now takes it whenever it is on in the
sketch being edited; the section comes back when Slice is turned off or
the sketch closes. A slice is hatched as it is without a section.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
semmelrinde
2026-11-02 00:02:59 +00:00
committed by GitHub
parent 0b90731096
commit cea07cbc66
+39 -10
View File
@@ -2766,22 +2766,25 @@ pub fn section_plane(app: &SolveApp) -> Option<(Vec3, Vec3)> {
scratch.execute("inspect.section", &p).ok()?;
return scratch.section;
}
// Slice (Sketch Palette): cut the model at the plane of the sketch being edited.
if app.session.section.is_none() {
let st = crate::open_meshing::shown_world(app);
if let Some(ss) = app.session.active_sketch.and_then(|s| st.sketch(s)).filter(|ss| ss.sketch.view.slice) {
return Some((ss.plane.origin, ss.plane.normal()));
}
}
app.session.section
slice_plane(app).or(app.session.section)
}
/// Slice (Sketch Palette): the plane of the sketch being edited, when Slice is on in it. It
/// stands in for a Section Analysis until it is turned off or the sketch closes: with the
/// section first, turning Slice on did nothing (#10705).
fn slice_plane(app: &SolveApp) -> Option<(Vec3, Vec3)> {
let id = app.session.active_sketch?;
let st = crate::open_meshing::shown_world(app);
let ss = st.sketch(id).filter(|ss| ss.sketch.view.slice)?;
Some((ss.plane.origin, ss.plane.normal()))
}
/// Whether the section [`section_plane`] shows has hatched cut faces: an open Section Analysis
/// dialog's Hatch option, else the section's own.
/// dialog's Hatch option, a Slice's always, else the section's own.
pub fn section_hatch(app: &SolveApp) -> bool {
match app.dialog.as_ref().map(|d| &d.kind) {
Some(crate::dialogs::Kind::Section { hatch, .. }) => *hatch,
_ => app.session.section_hatch,
_ => app.session.section_hatch || slice_plane(app).is_some(),
}
}
@@ -9929,6 +9932,32 @@ mod tests {
assert!(!legend(&mut h));
}
#[test]
fn a_sketch_slice_cuts_at_the_sketch_while_a_section_is_on() {
// #10705: with a Section Analysis on, turning Slice on in a sketch did nothing.
let mut h = crate::scenario::Harness::new();
h.app.run("solid.box", json!({"length":40,"width":30,"height":20,"body_name":"Block"})).unwrap();
h.app.run("construct.plane.offset", json!({"base":"XY","offset":10,"name":"Mid"})).unwrap();
h.app.run("sketch.create", json!({"plane":"Mid"})).unwrap();
h.app.run("inspect.section", json!({"plane":"XZ","offset":15,"hatch":false})).unwrap();
h.frames(2);
let across_y = |h: &crate::scenario::Harness| section_plane(&h.app).is_some_and(|(o, n)| n.y.abs() > 0.99 && (o.y.abs() - 15.0).abs() < 1e-9);
assert!(across_y(&h));
assert!(!section_hatch(&h.app));
h.app.run("sketch.options", json!({"slice":true})).unwrap();
h.frames(2);
let (o, n) = section_plane(&h.app).expect("the slice");
assert!(n.z.abs() > 0.99 && (o.z - 10.0).abs() < 1e-9, "{o:?} {n:?}");
assert!(section_hatch(&h.app), "a slice is hatched as it is without a section");
// Slice off, or the sketch closed: the section is back.
h.app.run("sketch.options", json!({"slice":false})).unwrap();
assert!(across_y(&h));
h.app.run("sketch.options", json!({"slice":true})).unwrap();
h.app.run("sketch.finish", json!({})).unwrap();
h.frames(2);
assert!(across_y(&h));
}
#[test]
fn a_section_leaves_the_origin_planes_and_axes_whole() {
// #1229: the origin planes and axes are reference geometry; the section plane cuts the