Sketch Palette, docked at the right while sketching: line type of the selected curves (normal, construction, centerline), Look At, and options kept with each sketch (sketch.options: Sketch Grid, Snap, Slice, Show Profile, Show Points, Show Dimensions, Show Constraints, Show Projected Geometries, 3D Sketch), the degrees of freedom, Finish Sketch. Slice cuts the model at the sketch plane; Snap off places points at the cursor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
2608ae6761
commit
bbd0a19260
10 files changed
+382
-7
No files matched your search
@@ -157,6 +157,9 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
CommandSpec::new("sketch.dimension_text", "Move Dimension Text", dimension_text)
|
||||
.enabled(in_sketch)
|
||||
.params("dimension: constraint id or parameter name; at: [x,y] text centre (sketch coordinates) | reset: true (default place)"),
|
||||
CommandSpec::new("sketch.options", "Sketch Palette Options", sketch_options).icon("sketch").params(
|
||||
"sketch?: id|name (default active); any of show_profile, show_points, show_dimensions, show_constraints, show_projected, grid, snap, slice, sketch_3d: bool. Returns them all",
|
||||
),
|
||||
CommandSpec::new("sketch.solve", "Solve Sketch", solve_cmd)
|
||||
.enabled(in_sketch)
|
||||
.noundo()
|
||||
@@ -1514,6 +1517,55 @@ fn move_point(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(json!({"sketch": info}))
|
||||
}
|
||||
|
||||
/// The Sketch Palette options of a sketch, by their palette names (true = shown / on).
|
||||
fn options_json(v: &solvecraft_sketch::SketchView) -> Value {
|
||||
json!({
|
||||
"show_profile": !v.hide_profile,
|
||||
"show_points": !v.hide_points,
|
||||
"show_dimensions": !v.hide_dimensions,
|
||||
"show_constraints": !v.hide_constraints,
|
||||
"show_projected": !v.hide_projected,
|
||||
"grid": !v.hide_grid,
|
||||
"snap": !v.no_snap,
|
||||
"slice": v.slice,
|
||||
"sketch_3d": v.three_d,
|
||||
})
|
||||
}
|
||||
|
||||
fn sketch_options(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let cmd = "sketch.options";
|
||||
let keys = ["show_profile", "show_points", "show_dimensions", "show_constraints", "show_projected", "grid", "snap", "slice", "sketch_3d"];
|
||||
if let Some(o) = p.as_object()
|
||||
&& let Some(k) = o.keys().find(|k| *k != "sketch" && !keys.contains(&k.as_str()))
|
||||
{
|
||||
return Err(bad(cmd, format!("unknown option `{k}`")));
|
||||
}
|
||||
let set = |k: &str| bool_(p, k);
|
||||
if keys.iter().all(|k| set(k).is_none()) {
|
||||
let id = target_sketch(s, p, cmd)?;
|
||||
return Ok(json!({"options": options_json(&s.doc.sketch(id)?.view)}));
|
||||
}
|
||||
let (v, info) = edit(s, p, cmd, false, |sk, _| {
|
||||
let v = &mut sk.view;
|
||||
let put = |k: &str, flag: &mut bool, shown_means_off: bool| {
|
||||
if let Some(b) = set(k) {
|
||||
*flag = if shown_means_off { !b } else { b };
|
||||
}
|
||||
};
|
||||
put("show_profile", &mut v.hide_profile, true);
|
||||
put("show_points", &mut v.hide_points, true);
|
||||
put("show_dimensions", &mut v.hide_dimensions, true);
|
||||
put("show_constraints", &mut v.hide_constraints, true);
|
||||
put("show_projected", &mut v.hide_projected, true);
|
||||
put("grid", &mut v.hide_grid, true);
|
||||
put("snap", &mut v.no_snap, true);
|
||||
put("slice", &mut v.slice, false);
|
||||
put("sketch_3d", &mut v.three_d, false);
|
||||
Ok(options_json(v))
|
||||
})?;
|
||||
Ok(json!({"options": v, "sketch": info}))
|
||||
}
|
||||
|
||||
fn solve_cmd(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let id = target_sketch(s, p, "sketch.solve")?;
|
||||
let st = s.model.state();
|
||||
|
||||
@@ -400,3 +400,36 @@ fn point_constraints_keep_the_first_pick() {
|
||||
assert!(same(&snap(&s, "p1"), &a0) && same(&snap(&s, "l1"), &l0));
|
||||
assert!(pt(&s, "p2").dist(solvecraft_geom::Vec2::new(3.0, -7.0)) < 1e-6, "{:?}", pt(&s, "p2"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Sketch Palette options
|
||||
|
||||
#[test]
|
||||
fn palette_options_are_kept_with_each_sketch() {
|
||||
let mut s = new_sketch();
|
||||
let o = run(&mut s, "sketch.options", json!({}));
|
||||
assert_eq!(o["options"]["show_dimensions"], true);
|
||||
assert_eq!(o["options"]["slice"], false);
|
||||
let o = run(&mut s, "sketch.options", json!({"show_dimensions": false, "snap": false, "slice": true, "sketch_3d": true}));
|
||||
assert_eq!(o["options"]["show_dimensions"], false);
|
||||
assert_eq!(o["options"]["snap"], false);
|
||||
assert_eq!(o["options"]["slice"], true);
|
||||
let v = sketch(&s).view;
|
||||
assert!(v.hide_dimensions && v.no_snap && v.slice && v.three_d && !v.hide_points);
|
||||
// Another sketch starts with the defaults; the first keeps its options after finishing.
|
||||
let first = s.active_sketch.expect("sketch");
|
||||
run(&mut s, "SketchStop", json!({}));
|
||||
run(&mut s, "SketchCreate", json!({"plane": "XZ"}));
|
||||
assert_eq!(sketch(&s).view, solvecraft_sketch::SketchView::default());
|
||||
let o = run(&mut s, "sketch.options", json!({"sketch": first}));
|
||||
assert_eq!(o["options"]["show_dimensions"], false);
|
||||
// Saved with the design.
|
||||
let text = serde_json::to_string(&s.doc.sketch(first).expect("first").clone()).expect("json");
|
||||
let back: Sketch = serde_json::from_str(&text).expect("parse");
|
||||
assert!(back.view.slice);
|
||||
assert!(s.execute("sketch.options", &json!({"bogus": true})).is_err());
|
||||
// Undo restores the option.
|
||||
run(&mut s, "sketch.options", json!({"show_points": false}));
|
||||
run(&mut s, "UndoCommand", json!({}));
|
||||
assert!(!sketch(&s).view.hide_points);
|
||||
}
|
||||
Reference in new issue
Block a user