Fillet and chamfer: refuse an edge pick far from every edge (#820)
Fixes #783.
This commit is contained in:
1 parent
53238fba5f
commit
69050c81d9
3 files changed
+56
-1
No files matched your search
@@ -751,9 +751,39 @@ fn edge_points(s: &Session, p: &Value, cmd: &str) -> Result<Vec<Vec3>> {
|
||||
return Err(bad(cmd, "select 1…1000 edges"));
|
||||
}
|
||||
let st = s.model.state();
|
||||
// A picked point must lie on an edge (within the distance the kernel re-finds an edge from)
|
||||
// of the body the feature names, or of any body: a pick far from every edge would round
|
||||
// whichever edge is nearest (#783). Each body's edges are worked out once.
|
||||
let named = str_(p, "body").filter(|n| st.body(n).is_some());
|
||||
let mut candidates: Option<Vec<(f64, Vec<solidcraft_kernel::EdgeInfo>)>> = None;
|
||||
let mut out = Vec::new();
|
||||
for e in a {
|
||||
if let Some(pt) = vec3(e).or_else(|| e.get("point").and_then(vec3)) {
|
||||
let bodies = candidates.get_or_insert_with(|| {
|
||||
// Mesh bodies have no edges to pick: rounding one is refused later, saying why.
|
||||
st.bodies
|
||||
.iter()
|
||||
.filter(|b| named.is_none_or(|n| b.name == n) && !b.body.is_mesh())
|
||||
.filter_map(|b| {
|
||||
let size = b.body.size();
|
||||
b.body.edges((size * 2e-3).max(1e-3)).ok().map(|edges| (size, edges))
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
let mut nearest = f64::INFINITY;
|
||||
let on_edge = bodies.iter().any(|(size, edges)| {
|
||||
let d = edges
|
||||
.iter()
|
||||
.flat_map(|e| e.points.windows(2))
|
||||
.filter_map(|w| Some(pt.dist_to_segment(*w.first()?, *w.get(1)?)))
|
||||
.fold(f64::INFINITY, f64::min);
|
||||
nearest = nearest.min(d);
|
||||
d <= size * 0.05 + 1e-3
|
||||
});
|
||||
if !on_edge && !bodies.is_empty() {
|
||||
let far = if nearest.is_finite() { format!("the nearest edge is {nearest:.3} mm away") } else { "there is no edge".to_string() };
|
||||
return Err(bad(cmd, format!("no edge at [{}, {}, {}]: {far}", pt.x, pt.y, pt.z)));
|
||||
}
|
||||
out.push(pt);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,31 @@ fn round_as_tall_as_a_disc_uses_up_its_wall() {
|
||||
assert!(rel(volume(&mut s), expect) < 2e-4, "{} vs {expect}", volume(&mut s));
|
||||
}
|
||||
|
||||
/// #783: an edge pick far from every edge (beside the body, above it, inside it, or on another
|
||||
/// body than the one named) is refused and adds nothing, instead of rounding the nearest edge;
|
||||
/// a pick on an edge, or a little off it as a click lands, still works.
|
||||
#[test]
|
||||
fn edge_picks_far_from_every_edge_are_refused() {
|
||||
let mut s = Session::default();
|
||||
for (name, x) in [("A", 0), ("B", 40), ("C", 80), ("D", 120)] {
|
||||
run(&mut s, "solid.box", json!({"length": 20, "width": 20, "height": 10, "corner": [x, 0, 0], "operation": "new", "body_name": name}));
|
||||
}
|
||||
run(&mut s, "solid.fillet", json!({"body": "A", "edges": [[10, 0, 10]], "radius": 1}));
|
||||
run(&mut s, "solid.fillet", json!({"body": "B", "edges": [[50, 0.4, 10.3]], "radius": 1}));
|
||||
let features = s.doc.features.len();
|
||||
for (id, p, far) in [
|
||||
("solid.fillet", json!({"body": "B", "edges": [[50, -15, 10]], "radius": 1}), "15.0"),
|
||||
("solid.chamfer", json!({"body": "C", "edges": [[90, 10, 40]], "distance": 1}), "31.623 mm"),
|
||||
("solid.fillet", json!({"edges": [[130, 10, 5]], "radius": 1}), "11.180 mm"),
|
||||
("solid.fillet", json!({"body": "C", "edges": [[10, 20, 10]], "radius": 1}), "mm away"),
|
||||
("solid.press_pull", json!({"edges": [[50, -15, 10]], "distance": 1}), "15.0"),
|
||||
] {
|
||||
let err = s.execute(id, &p).expect_err(&format!("{id} {p}")).to_string();
|
||||
assert!(err.contains("no edge at") && err.contains(far), "{id} {p}: {err}");
|
||||
}
|
||||
assert_eq!(s.doc.features.len(), features);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fillet_as_wide_as_a_face_rounds_it_off() {
|
||||
// #199: 14 x 6 x 10 box, the four vertical edges at r = 3 (half the 6 mm end faces).
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{"command": "sketch.line", "params": {"points": [[0, 0], [40, 0], [40, 6], [6, 6], [6, 30], [0, 30]], "closed": true, "ids": ["a", "b", "c", "d", "e", "f"]}},
|
||||
{"command": "sketch.finish", "params": {}},
|
||||
{"command": "solid.extrude", "params": {"distance": "width", "direction": "negative", "body_name": "Bracket"}},
|
||||
{"command": "solid.fillet", "params": {"edges": [[40, 30, 6]], "radius": 2}},
|
||||
{"command": "solid.fillet", "params": {"edges": [[40, -30, -6]], "radius": 2}},
|
||||
{"command": "sketch.create", "params": {"plane": "XY", "name": "Holes"}},
|
||||
{"command": "sketch.circle.center", "params": {"center": [25, 15], "diameter": 8}},
|
||||
{"command": "sketch.circle.center", "params": {"center": [25, 45], "diameter": 8}},
|
||||
|
||||
Reference in new issue
Block a user