Sketch: symmetry about the origin point or an origin axis (#1318)

Fixes #1075. sketch.constraint.symmetry takes a centre point (the origin or any sketch point) as well as a line; the Symmetry tool's third pick may be the origin point or the sketch's own X/Y origin axis. Checked on main + this branch: cargo check --workspace, the engine cmd::sketch tests (257) and the UI symmetry pick tests.
This commit is contained in:
DuBearte authored and GitHub committed 2026-10-15 03:47:37 -04:00
1 parent 6f115ad740
commit 3e13eb6392
4 files changed
+245 -1

No files matched your search

+33
View File
@@ -16,6 +16,10 @@ mod display_preview_tests;
#[path = "sketch_neutral_click_tests.rs"]
mod neutral_click_tests;
#[cfg(test)]
#[path = "symmetry_pick_tests.rs"]
mod symmetry_pick_tests;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Kind {
/// Click points; `n` points complete the shape (0 = chain until finished).
@@ -189,8 +193,12 @@ pub fn on_click(app: &mut SolveApp, proj: &Proj, pos: Pos2) {
}
Kind::Pick(n) => {
let hits = pick(app, proj, pos);
// Symmetry's third pick may be an origin axis lying along the sketch's own x or y
// (#1075); the command names those `x` / `y`.
let axis_ok = tool.cmd == "sketch.constraint.symmetry" && tool.picks.len() == 2;
if let Some(id) = hits.iter().find_map(|h| match h {
Hit::SketchPoint { id, .. } | Hit::SketchCurve { id, .. } => Some(id.clone()),
Hit::Axis { name } if axis_ok => sketch_axis_of(app, name).map(str::to_string),
_ => None,
}) {
tool.picks.push(id);
@@ -455,6 +463,31 @@ pub(crate) fn projection_preselection(selection: &[solidcraft_engine::Sel]) -> O
.collect()
}
/// `x` or `y` when the origin axis `name` is the active sketch's own x or y axis: along it, and
/// through the sketch's origin.
fn sketch_axis_of(app: &SolveApp, name: &str) -> Option<&'static str> {
use solidcraft_engine::geom::Vec3;
let dir = match name {
"X" => Vec3::X,
"Y" => Vec3::Y,
"Z" => Vec3::Z,
_ => return None,
};
let st = app.session.world_state();
let plane = st.sketch(app.session.active_sketch?)?.plane;
let o = plane.origin;
if (o - dir * o.dot(dir)).len() > 1e-6 {
return None;
}
if plane.x.dot(dir).abs() > 1.0 - 1e-9 {
Some("x")
} else if plane.y.dot(dir).abs() > 1.0 - 1e-9 {
Some("y")
} else {
None
}
}
fn run_pick(app: &mut SolveApp, t: &Tool) {
let k = &t.picks;
let params = match t.cmd {