forked from 1b-agent/opencadstudio-upstream
fix(grip): stop double-offsetting the UCS grip snap marker
The extension anchors needed the same pane-to-canvas lift the snap marker already got, but the block that added it was placed next to the one that was already there rather than merged into it, so `screen` took the tile origin twice. A single full-canvas tile has no origin to add, so it only shows once the viewport is split. Fold the anchors into the existing block. Also require the ray to pass through the snapped point before offering it as a distance reference. Only four acquisitions are kept and the oldest is dropped as new ones arrive, so the ray that produced a snap can be gone by the time a distance is typed; picking the nearest survivor unconditionally sent the point off along an unrelated ray instead of falling back to plain point input. `extension_snap` projects onto the ray in exact f64, so the tolerance only has to clear rounding, scaled with the coordinate to hold at UTM magnitudes. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
687bc2079d
commit
b8f9727a27
2 files changed
+19
-7
No files matched your search
@@ -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);
|
||||
|
||||
+17
@@ -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));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user