diff --git a/src/app/update/viewport.rs b/src/app/update/viewport.rs index b62a496ad..ab37cd726 100644 --- a/src/app/update/viewport.rs +++ b/src/app/update/viewport.rs @@ -2043,24 +2043,19 @@ impl OpenCADStudio { let world = snap_hit.map(|s| s.world).unwrap_or(raw); self.tabs[i].snap_result = snap_hit; if let Some(s) = self.tabs[i].snap_result.as_mut() { + // Snap marker and its extension anchors are pane-local; lift them to + // absolute canvas px. s.screen.x += tile_b.x; s.screen.y += tile_b.y; - if let Some(base) = s.extension_base.as_mut() { base.x += tile_b.x; base.y += tile_b.y; } - if let Some(base) = s.extension_base2.as_mut() { base.x += tile_b.x; base.y += tile_b.y; } } - if let Some(s) = self.tabs[i].snap_result.as_mut() { - // Snap marker is pane-local; lift it to absolute canvas px. - s.screen.x += tile_b.x; - s.screen.y += tile_b.y; - } use acadrust::types::Vector3; let v3 = |d: glam::DVec3| Vector3::new(d.x, d.y, d.z); diff --git a/src/snap.rs b/src/snap.rs index 9636dd505..8cfb2c96a 100644 --- a/src/snap.rs +++ b/src/snap.rs @@ -1657,6 +1657,23 @@ impl Snapper { let unit_dir = glam::DVec3::new(dir.x / len, dir.y / len, 0.0); + // The ray has to actually pass through the snapped point. Only + // four acquisitions are kept and the oldest is dropped as new + // ones come in, so by the time a typed distance arrives the ray + // that produced this snap may be gone — without this the nearest + // surviving ray wins by default and the distance flies off along + // it. Failing here instead leaves the caller on plain point input. + // + // `extension_snap` builds the point by exact f64 projection onto + // this same ray, so a match sits on it to rounding: the tolerance + // only has to clear f64 noise, and scaling it with the coordinate + // keeps that true at UTM magnitudes. (`extension_bases_screen` + // answers the same question in screen pixels because it also has + // to catch a *crossing* base, which is a looser fit than this.) + let tol = 1e-9_f64.max(2e-12 * origin.x.abs().max(origin.y.abs())); + if err2 > tol * tol { + continue; + } if best.as_ref().map_or(true, |(best_err, _, _)| err2 < *best_err) { best = Some((err2, origin, unit_dir)); }