Construction axes, points and planes resolve their picks against the model as their component sees it (in the root, every placement, pasted instances too), and a Hole picked on another component's body cuts that body. components-arm 355 -> 502/594 and joints-hinge 304/390 -> 371/408 in the action matrix. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
083ddf7722
commit
2a434d59c3
5 files changed
+208
-133
No files matched your search
@@ -1310,7 +1310,33 @@ fn hole(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Some(v) => Some(vec3(v).ok_or_else(|| bad(cmd, "`to` must be a point [x, y, z] on the face to drill to"))?),
|
||||
None => None,
|
||||
};
|
||||
add_feature(s, p, FeatureKind::Hole { position, direction, diameter, depth, hole: kind, points: points.map(|x| x.0), thread, to })
|
||||
// A hole picked on a body of another component (a moved one, shown where it is placed) cuts
|
||||
// that body: the pick is already in that body's frame, and the component's own bodies alone
|
||||
// would leave nothing to cut.
|
||||
let mut p = p.clone();
|
||||
if points.is_none()
|
||||
&& p.get("participants").is_none()
|
||||
&& let Some(body) = body_of_other_component_at(s, position)
|
||||
{
|
||||
p["participants"] = json!([body]);
|
||||
}
|
||||
add_feature(s, &p, FeatureKind::Hole { position, direction, diameter, depth, hole: kind, points: points.map(|x| x.0), thread, to })
|
||||
}
|
||||
|
||||
/// The body whose face is nearest `p` (within its pick tolerance), when it belongs to another
|
||||
/// component than the active one.
|
||||
fn body_of_other_component_at(s: &Session, p: Vec3) -> Option<String> {
|
||||
let st = s.model.state();
|
||||
let (_, body) = st
|
||||
.bodies
|
||||
.iter()
|
||||
.filter(|b| !b.body.is_mesh())
|
||||
.filter_map(|b| {
|
||||
let (d, _) = solidcraft_doc::appearance::nearest_face(b, p)?;
|
||||
(d <= solidcraft_doc::appearance::pick_tolerance(b)).then_some((d, b))
|
||||
})
|
||||
.min_by(|a, b| a.0.total_cmp(&b.0))?;
|
||||
(s.doc.model_body_component(body) != s.active_component).then(|| body.name.clone())
|
||||
}
|
||||
|
||||
/// The points of a sketch a hole drills at when only the sketch is given.
|
||||
|
||||
@@ -252,3 +252,37 @@ fn root_sketch_on_a_moved_components_face() {
|
||||
let pts = sketch_world_points(&mut s, "Top");
|
||||
assert!(pts.iter().any(|p| near(*p, Vec3::new(-30.0, 40.0, 25.0))), "{pts:?}");
|
||||
}
|
||||
|
||||
/// (#558) With the root active, construction geometry, a hole and Press Pull picked on a moved
|
||||
/// component land on it where it is shown, and so do picks on a pasted instance.
|
||||
#[test]
|
||||
fn root_picks_on_a_moved_component_build_where_it_is_shown() {
|
||||
let mut s = moved_part();
|
||||
run(&mut s, "component.activate", json!({"component": "root"}));
|
||||
// The block spans world x 50…80, y 0…20, z 0…10.
|
||||
run(&mut s, "construct.axis.edge", json!({"edge": {"edge": [65, 0, 0]}, "name": "FrontEdge"}));
|
||||
run(
|
||||
&mut s,
|
||||
"construct.plane.three_points",
|
||||
json!({"a": {"vertex": [50, 0, 10]}, "b": {"vertex": [80, 0, 10]}, "c": {"vertex": [50, 20, 10]}, "name": "Lid"}),
|
||||
);
|
||||
let lid = crate::view::construction_planes(&s).into_iter().find(|(_, n, _)| n == "Lid").unwrap().2;
|
||||
assert!((lid.origin.z - 10.0).abs() < 1e-6 && lid.normal().z.abs() > 1.0 - 1e-9, "{lid:?}");
|
||||
let st = s.model.state();
|
||||
let axis = st.construct.iter().find(|c| c.name == "FrontEdge").map(|c| c.geom.clone()).unwrap();
|
||||
let solidcraft_doc::construct::ConstructGeom::Axis { origin, dir } = axis else { panic!("{axis:?}") };
|
||||
assert!(origin.y.abs() < 1e-6 && origin.z.abs() < 1e-6 && dir.x.abs() > 1.0 - 1e-9, "{origin:?} {dir:?}");
|
||||
let v0 = volume(&mut s);
|
||||
run(&mut s, "solid.hole", json!({"position": [60, 10, 10], "diameter": 4, "depth": 5}));
|
||||
let v1 = volume(&mut s);
|
||||
assert!(v1 < v0 - 1.0, "the hole cut the moved block: {v0} {v1}");
|
||||
run(&mut s, "solid.press_pull", json!({"face": [80, 10, 5], "distance": 2}));
|
||||
assert!(volume(&mut s) > v1 + 1.0, "press pull grew the moved block");
|
||||
assert!(s.model.results.iter().all(|r| r.error.is_none()), "{:?}", s.model.results);
|
||||
|
||||
// A pasted instance 40 mm further along y.
|
||||
run(&mut s, "occurrence.copy", json!({"component": "Part", "translate": [0, 40, 0]}));
|
||||
run(&mut s, "construct.plane.along_path", json!({"path": {"edge": [65, 40, 0]}, "t": 0.5, "name": "Across"}));
|
||||
let across = crate::view::construction_planes(&s).into_iter().find(|(_, n, _)| n == "Across").unwrap().2;
|
||||
assert!((across.origin.y - 40.0).abs() < 1e-6, "{across:?}");
|
||||
}
|
||||
Reference in new issue
Block a user