fix(doc): To Object takes the face at the pick, not the first body near it (#429)

object_height, curved_target and curved_target_any took the first solid body with any face
within its pick tolerance of the To Object point. That tolerance is 5 % of the body's size,
so a large body beside a small target took picks made on the target: a ridge extruded up
to a post 2 mm above a plate treated the plate as the target, nothing trimmed the tool, and
it ran past the post (to x 9.08 instead of -2.31).

They now share face_at: the nearest face over every solid body, still within that body's
tolerance. appearance gains nearest_face (the face and its distance) and pick_tolerance,
which face_index_at now uses as well.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MqriusandClaude Opus 5.5 authored and GitHub committed 2026-10-12 18:55:47 -04:00
1 parent 968a22897c
commit 1d7450b04c
3 files changed
+76 -35

No files matched your search

+12 -2
View File
@@ -239,6 +239,12 @@ impl Document {
/// The B-rep face of a body nearest a point (within 5% of the body's size).
pub fn face_index_at(b: &crate::ModelBody, p: Vec3) -> Option<usize> {
let (d, f) = nearest_face(b, p)?;
(d <= pick_tolerance(b)).then_some(f)
}
/// The face of `b` nearest `p` and how far it is, however far.
pub fn nearest_face(b: &crate::ModelBody, p: Vec3) -> Option<(f64, usize)> {
let m = b.mesh();
let mut best: Option<(f64, u32)> = None;
for (t, f) in m.triangles.iter().zip(&m.tri_face) {
@@ -248,8 +254,12 @@ pub fn face_index_at(b: &crate::ModelBody, p: Vec3) -> Option<usize> {
best = Some((d, *f));
}
}
let (d, f) = best?;
(d <= b.body.size() * 0.05 + 1e-6).then_some(f as usize)
best.map(|(d, f)| (d, f as usize))
}
/// How far from a face of `b` a picked point may lie and still pick it (`face_index_at`).
pub fn pick_tolerance(b: &crate::ModelBody) -> f64 {
b.body.size() * 0.05 + 1e-6
}
/// The point of triangle abc nearest p.