Resolve #159 against current sketch preselection

This commit is contained in:
bherbruck committed 2026-10-11 17:23:12 -04:00
commit 78aa2aacfb
3 files changed
+96

No files matched your search

+2
View File
@@ -327,6 +327,8 @@ fn run_shape(app: &mut SolveApp, t: &Tool) -> Result<Vec<String>, String> {
pub(crate) fn constraint_preselection(command: &str, selection: &[solvecraft_engine::Sel]) -> Option<Value> { pub(crate) fn constraint_preselection(command: &str, selection: &[solvecraft_engine::Sel]) -> Option<Value> {
use solvecraft_engine::Sel::{SketchCurve, SketchPoint}; use solvecraft_engine::Sel::{SketchCurve, SketchPoint};
match (command, selection) { match (command, selection) {
("sketch.constraint.horizontal_vertical", [SketchCurve { id }]) => Some(json!({"line":id})),
("sketch.constraint.horizontal_vertical", [SketchPoint { id: a }, SketchPoint { id: b }]) if a != b => Some(json!({"points":[a,b]})),
("sketch.constraint.coincident", [a, b]) => { ("sketch.constraint.coincident", [a, b]) => {
let entity = |s: &solvecraft_engine::Sel| match s { let entity = |s: &solvecraft_engine::Sel| match s {
SketchPoint { id } | SketchCurve { id } => Some(id.clone()), SketchPoint { id } | SketchCurve { id } => Some(id.clone()),
+91
View File
@@ -4,6 +4,97 @@ use serde_json::json;
use solvecraft_engine::sketch::ConstraintKind; use solvecraft_engine::sketch::ConstraintKind;
use solvecraft_ui_egui::scenario::Harness; use solvecraft_ui_egui::scenario::Harness;
#[test]
fn horizontal_vertical_uses_preselected_line_and_preserves_rejection() {
for fixed in [false, true] {
let mut h = Harness::new();
h.run(&json!([
{"call":"engine.execute","params":{"command":"sketch.create","params":{"plane":"XY"}}},
{"call":"engine.execute","params":{"command":"sketch.line","params":{"points":[[10,10],[40,13]],"infer":false}}},
{"call":"ui.view","params":{"view":"top"}}
]))
.unwrap();
if fixed {
h.app.session.execute("sketch.constraint.fix", &json!({"entity":"l1"})).unwrap();
}
h.run(&json!([{"click":{"sketch":[25,11.5]}}])).unwrap();
assert_eq!(h.app.session.selection.len(), 1);
let selection = h.app.session.selection.clone();
let before = serde_json::to_value(&h.app.session.doc).unwrap();
let undo = h.app.session.undo.len();
h.run(&json!([{"start":"sketch.constraint.horizontal_vertical"}])).unwrap();
assert_eq!(h.app.status.as_ref().is_some_and(|(_, _, error)| *error), fixed);
if fixed {
assert_eq!(serde_json::to_value(&h.app.session.doc).unwrap(), before);
assert_eq!(h.app.session.selection, selection);
assert_eq!(h.app.session.undo.len(), undo);
} else {
let sk = &h.app.session.model.state().sketches[0].sketch;
let a = sk.point(sk.resolve_point("l1.start").unwrap()).unwrap();
let b = sk.point(sk.resolve_point("l1.end").unwrap()).unwrap();
assert!((a.y - b.y).abs() < 1e-6);
assert_eq!(h.app.session.undo.len(), undo + 1);
assert!(h.app.session.selection.is_empty());
}
assert!(h.app.tool.is_none());
}
}
#[test]
fn horizontal_vertical_leaves_ambiguous_preselection_to_pick_tool() {
use solvecraft_engine::Sel;
for selection in [
vec![Sel::SketchPoint { id: "origin".into() }],
vec![Sel::SketchPoint { id: "origin".into() }, Sel::SketchCurve { id: "c1".into() }],
vec![Sel::SketchPoint { id: "origin".into() }, Sel::SketchPoint { id: "c1.center".into() }, Sel::SketchCurve { id: "c1".into() }],
] {
let mut h = Harness::new();
h.app.session.execute("sketch.create", &json!({"plane":"XY"})).unwrap();
h.app.session.execute("sketch.circle.center", &json!({"center":[20,3],"radius":5})).unwrap();
h.app.session.selection = selection.clone();
let undo = h.app.session.undo.len();
h.run(&json!([{"start":"sketch.constraint.horizontal_vertical"}])).unwrap();
assert!(h.app.tool.as_ref().unwrap().picks.is_empty());
assert_eq!(h.app.session.undo.len(), undo);
assert_eq!(h.app.session.selection, selection);
assert!(!h.app.status.as_ref().is_some_and(|(_, _, error)| *error));
}
}
#[test]
fn horizontal_vertical_uses_preselected_points() {
for center in [[20.0, 3.0], [3.0, 20.0]] {
for reverse in [false, true] {
let mut h = Harness::new();
let (first, second) = if reverse { (center, [0.0, 0.0]) } else { ([0.0, 0.0], center) };
h.run(&json!([
{"call":"engine.execute","params":{"command":"sketch.create","params":{"plane":"XY"}}},
{"call":"engine.execute","params":{"command":"sketch.circle.center","params":{"center":center,"radius":5}}},
{"call":"ui.view","params":{"view":"top"}},
{"click":{"sketch":first}},
{"click":{"sketch":second},"shift":true}
]))
.unwrap();
assert_eq!(h.app.session.selection.len(), 2);
let before = serde_json::to_value(&h.app.session.doc).unwrap();
let undo = h.app.session.undo.len();
h.run(&json!([{"start":"sketch.constraint.horizontal_vertical"}])).unwrap();
assert!(!h.app.status.as_ref().is_some_and(|(_, _, error)| *error));
let sk = &h.app.session.model.state().sketches[0].sketch;
let p = sk.point(sk.resolve_point("c1.center").unwrap()).unwrap();
assert!((if center[0] > center[1] { p.y } else { p.x }).abs() < 1e-6);
assert!(h.app.tool.is_none());
assert!(h.app.session.selection.is_empty());
assert_eq!(h.app.session.undo.len(), undo + 1);
let after = serde_json::to_value(&h.app.session.doc).unwrap();
h.app.session.execute("edit.undo", &json!({})).unwrap();
assert_eq!(serde_json::to_value(&h.app.session.doc).unwrap(), before);
h.app.session.execute("edit.redo", &json!({})).unwrap();
assert_eq!(serde_json::to_value(&h.app.session.doc).unwrap(), after);
}
}
}
#[test] #[test]
fn horizontal_vertical_aligns_origin_and_circle_center() { fn horizontal_vertical_aligns_origin_and_circle_center() {
for (center, horizontal) in [([20.0, 3.0], true), ([3.0, 20.0], false)] { for (center, horizontal) in [([20.0, 3.0], true), ([3.0, 20.0], false)] {
+3
View File
@@ -96,6 +96,9 @@ distinct straight lines. Two lines join their closest pair of endpoints; the fir
picked line stays in place when the existing constraints allow it. Pick endpoints picked line stays in place when the existing constraints allow it. Pick endpoints
explicitly when you want to connect a different pair. explicitly when you want to connect a different pair.
Horizontal/Vertical also applies immediately to one selected line or two distinct selected
points. Shift-click to add the second point before choosing the constraint.
For Parallel, Perpendicular, Equal, Tangent, Concentric and Collinear, select exactly two For Parallel, Perpendicular, Equal, Tangent, Concentric and Collinear, select exactly two
sketch curves (Shift-click to add the second) and choose the constraint to apply it immediately. sketch curves (Shift-click to add the second) and choose the constraint to apply it immediately.
You can also start the constraint first and then pick its curves. An incomplete or mixed You can also start the constraint first and then pick its curves. An incomplete or mixed