Sketches on body faces follow their face: the plane is a face reference found again on each evaluation (same normal, nearest the picked point), and face extrudes (Extrude on a face, Press Pull) use the linked projection of the face's edges instead of a frozen copy, so they follow when earlier features change
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
2db9e66048
commit
2ec34c6e78
8 files changed
+74
-7
No files matched your search
@@ -99,10 +99,15 @@ pub(super) fn sketch_of_face(s: &mut Session, point: Vec3, cmd: &str) -> Result<
|
||||
let spec = crate::find_command(id).ok_or_else(|| bad(cmd, id))?;
|
||||
(spec.run)(s, &p)
|
||||
};
|
||||
let r = run(s, "SketchCreate", json!({"plane": {"face": [inside.x, inside.y, inside.z]}}))?;
|
||||
let r = run(s, "SketchCreate", json!({"plane": {"face": [inside.x, inside.y, inside.z]}, "project_edges": true}))?;
|
||||
let sid = r.get("sketch").and_then(Value::as_u64).ok_or_else(|| bad(cmd, "could not start a sketch on the face"))?;
|
||||
s.refresh();
|
||||
let plane = s.model.state().sketch(sid).map(|ss| ss.plane).ok_or_else(|| bad(cmd, "could not start a sketch on the face"))?;
|
||||
// The face's edges came in as linked projections: they follow the face when earlier
|
||||
// features change, so nothing is copied.
|
||||
if r.get("projected").is_some_and(|x| !x.is_null()) {
|
||||
return Ok((sid, plane.to_local(inside)));
|
||||
}
|
||||
for e in &edges {
|
||||
let pts: Vec<Vec2> = e.iter().map(|p| plane.to_local(*p)).collect();
|
||||
let (Some(first), Some(last)) = (pts.first().copied(), pts.last().copied()) else { continue };
|
||||
|
||||
@@ -318,7 +318,7 @@ pub(super) fn plane_ref(s: &Session, p: &Value, cmd: &str) -> Result<PlaneRef> {
|
||||
}
|
||||
}
|
||||
let pl = found.ok_or_else(|| bad(cmd, "no planar face at that point"))?;
|
||||
PlaneRef::Custom { plane: pl }
|
||||
PlaneRef::Face { plane: pl, at: fp }
|
||||
} else {
|
||||
let origin = v.get("origin").and_then(vec3).unwrap_or(Vec3::ZERO);
|
||||
let x = v.get("x_dir").and_then(vec3).ok_or_else(|| bad(cmd, "plane needs x_dir"))?;
|
||||
|
||||
@@ -977,3 +977,14 @@ fn components_export_as_step_assembly() {
|
||||
assert_eq!(xs.len(), 2);
|
||||
assert!(((xs[0] - xs[1]).abs() - 20.0).abs() < 1e-6, "{xs:?}");
|
||||
}
|
||||
|
||||
/// A face extrude follows its face when earlier features change.
|
||||
#[test]
|
||||
fn face_extrude_follows_edits() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 40, "width": 30, "height": 20, "name": "Base"}));
|
||||
run(&mut s, "Extrude", json!({"face": [20, 15, 20], "distance": 10, "operation": "join", "name": "Pad"}));
|
||||
assert!(rel(volume(&mut s), 40.0 * 30.0 * 30.0) < 1e-6);
|
||||
run(&mut s, "timeline.edit", json!({"feature": "Base", "set": {"height": "25", "length": "50"}}));
|
||||
assert!(rel(volume(&mut s), 50.0 * 30.0 * 35.0) < 1e-6, "{}", volume(&mut s));
|
||||
}
|
||||
Reference in new issue
Block a user