Sketch inline dimensions while drawing (line length/angle, rectangle width/height, circle diameter, arc radius/sweep, polygon radius/sides, slot length/width): boxes sit on what they measure, typing goes into the first box and locks it, Tab moves on, Enter places the shape, typed values become dimension constraints (expressions and units); Press Pull (Q: faces extrude/cut by sign, edges fillet), X toggles construction on selected curves, Move dialog (M) with preview

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-07 21:40:14 +00:00
1 parent ea3dd0ed6e
commit eb22a149b1
11 files changed
+411 -25

No files matched your search

+22
View File
@@ -65,6 +65,11 @@ pub static COMMANDS: &[CommandSpec] = &[
.icon("plane")
.params("base: XY|XZ|YZ|plane name; axis: X|Y|Z|{origin, dir}; angle: expr; name?"),
CommandSpec::new("FusionSplitBodyCommand", "Split Body", split_body).at("SOLID", "MODIFY").icon("split").params("body: name; plane: XY|XZ|YZ|plane name|{origin, normal}"),
CommandSpec::new("FusionPressPullCommand", "Press Pull", press_pull)
.at("SOLID", "MODIFY")
.icon("presspull")
.key("Q")
.params("face: [x,y,z] and distance: expr (positive adds material, negative cuts), or edges: [[x,y,z]…] and distance (a fillet)"),
CommandSpec::new("FusionMoveCommand", "Move/Copy", move_bodies).at("SOLID", "MODIFY").icon("move").key("M").params("bodies: [names]; translate?: [x,y,z] (exprs or numbers); axis?: [x,y,z]; angle?: expr"),
];
@@ -318,6 +323,23 @@ fn edge_points(s: &Session, p: &Value, cmd: &str) -> Result<Vec<Vec3>> {
Ok(out)
}
/// Press Pull: a face moves along its normal (an extrude that joins outward or cuts inward); an
/// edge is rounded (a fillet).
fn press_pull(s: &mut Session, p: &Value) -> Result<Value> {
let cmd = "FusionPressPullCommand";
let distance = req_expr(cmd, p, "distance")?;
if p.get("edges").is_some() {
return fillet(s, &json!({"edges": p.get("edges"), "radius": distance}));
}
let face = p.get("face").ok_or_else(|| bad(cmd, "needs `face` or `edges`"))?;
let d = s.doc.eval(&distance, Kind::Length).map_err(|e| bad(cmd, format!("distance: {e}")))?;
if d.abs() < 1e-9 {
return Err(bad(cmd, "the distance must not be zero"));
}
let (dist, dir, op) = if d > 0.0 { (distance, "positive", "join") } else { (format!("-({distance})"), "negative", "cut") };
extrude(s, &json!({"face": face, "distance": dist, "direction": dir, "operation": op}))
}
fn fillet(s: &mut Session, p: &Value) -> Result<Value> {
let cmd = "FusionFilletEdgesCommand";
let edges = edge_points(s, p, cmd)?;
+1
View File
@@ -147,6 +147,7 @@ pub static COMMANDS: &[CommandSpec] = &[
CommandSpec::new("sketch.construction", "Normal/Construction", construction)
.at("SKETCH", "CREATE")
.icon("construction")
.key("X")
.enabled(in_sketch)
.params("curves: [ids], value?: bool (default toggles)"),
CommandSpec::new("sketch.delete", "Delete Sketch Entities", sketch_delete)
+16
View File
@@ -526,6 +526,22 @@ fn preview_of_an_edit() {
assert!(Arc::ptr_eq(&doc, &s.doc));
}
/// Press Pull: positive pulls a face out, negative pushes it in (a cut), edges get a fillet.
#[test]
fn press_pull() {
let mut s = Session::default();
run(&mut s, "PrimitiveBox", json!({"length": 40, "width": 30, "height": 20}));
run(&mut s, "FusionPressPullCommand", json!({"face": [20, 15, 20], "distance": 5}));
assert!(rel(volume(&mut s), 40.0 * 30.0 * 25.0) < 1e-6);
run(&mut s, "FusionPressPullCommand", json!({"face": [20, 15, 25], "distance": "-10"}));
assert!(rel(volume(&mut s), 40.0 * 30.0 * 15.0) < 1e-6);
assert!(s.execute("FusionPressPullCommand", &json!({"face": [20, 15, 15], "distance": 0})).is_err());
let mut s = Session::default();
run(&mut s, "PrimitiveBox", json!({"length": 40, "width": 30, "height": 20}));
run(&mut s, "FusionPressPullCommand", json!({"edges": [[0, 0, 7]], "distance": 3}));
assert!(rel(volume(&mut s), 24000.0 - (9.0 - PI * 9.0 / 4.0) * 20.0) < 2e-4);
}
/// Extruding a planar body face (press-pull style): the face boundary becomes a sketch profile.
#[test]
fn extrude_a_body_face() {