forked from 1b-agent/opencadstudio-upstream
fix(snap): stop Extension tracking points from vanishing while in use
Extension-driven acquisition (OTRACK off) acquired any dwelled snap point, including the extension foot the cursor paused on while tracing an extension. Each such spurious acquisition filled the 4-point buffer and evicted, oldest-first, the endpoint the user had actually acquired — so after a few pauses its + marker and its extension disappeared. Restrict Extension-driven acquisition to real segment endpoints (points with an incident edge); midpoints, centres, intersections and extension feet are ignored. OTRACK still acquires any snap point. Refs #262 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
d93bcda889
commit
f491e8436b
1 file changed
+51
-7
+51
-7
@@ -253,6 +253,13 @@ impl Snapper {
|
||||
self.dwell_acquired = false;
|
||||
return;
|
||||
}
|
||||
// With OTRACK off, acquisition is Extension-driven, and Extension tracks
|
||||
// a line only from a real segment endpoint — so acquire endpoints only.
|
||||
// This stops a paused cursor on an extension foot (or a midpoint/centre)
|
||||
// from being acquired and evicting, through the 4-point cap, the very
|
||||
// endpoint the user acquired — the reason the marker vanished after a
|
||||
// few pauses (#262). OTRACK keeps acquiring any snap point.
|
||||
let endpoints_only = !self.otrack_enabled;
|
||||
// The cursor must rest near a snap point for this long before it is
|
||||
// acquired, so that brushing past snap points while moving the mouse
|
||||
// does not create accidental tracking points.
|
||||
@@ -263,7 +270,7 @@ impl Snapper {
|
||||
None => {
|
||||
// Leaving all geometry: capture the point we were dwelling on if
|
||||
// it qualified, before the reset loses it.
|
||||
self.acquire_on_leave(now, DWELL_MS, wires);
|
||||
self.acquire_on_leave(now, DWELL_MS, wires, endpoints_only);
|
||||
self.last_snap_world = None;
|
||||
self.dwell_since = None;
|
||||
self.dwell_acquired = false;
|
||||
@@ -298,14 +305,14 @@ impl Snapper {
|
||||
self.tracking_dirs.remove(idx);
|
||||
}
|
||||
}
|
||||
None => self.acquire_tracking_point(p, wires),
|
||||
None => self.acquire_tracking_point(p, wires, endpoints_only),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Moved to a different snap point: capture the previous one
|
||||
// first if it was dwelt on long enough, so a pause-then-drag
|
||||
// gesture reliably acquires it even without in-place events.
|
||||
self.acquire_on_leave(now, DWELL_MS, wires);
|
||||
self.acquire_on_leave(now, DWELL_MS, wires, endpoints_only);
|
||||
self.last_snap_world = Some(p);
|
||||
self.dwell_since = Some(now);
|
||||
self.dwell_acquired = false;
|
||||
@@ -318,7 +325,7 @@ impl Snapper {
|
||||
/// it is already tracked; drops the oldest when the 4-point cap is reached.
|
||||
/// Edge directions are scanned once here, at acquisition, so OTRACK can align
|
||||
/// to a segment's extension without rescanning geometry per move (#219).
|
||||
fn acquire_tracking_point(&mut self, p: Vec3, wires: &[WireModel]) {
|
||||
fn acquire_tracking_point(&mut self, p: Vec3, wires: &[WireModel], endpoints_only: bool) {
|
||||
if self
|
||||
.tracking_points
|
||||
.iter()
|
||||
@@ -326,6 +333,13 @@ impl Snapper {
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Edge directions double as an endpoint test: a point with no incident
|
||||
// segment — a midpoint, centre, intersection or extension foot — has
|
||||
// none. Extension-driven acquisition (#262) keeps only endpoints.
|
||||
let dirs = edge_dirs_at(p, wires);
|
||||
if endpoints_only && dirs.is_empty() {
|
||||
return;
|
||||
}
|
||||
if self.tracking_points.len() >= 4 {
|
||||
self.tracking_points.remove(0);
|
||||
if !self.tracking_dirs.is_empty() {
|
||||
@@ -333,7 +347,7 @@ impl Snapper {
|
||||
}
|
||||
}
|
||||
self.tracking_points.push(p);
|
||||
self.tracking_dirs.push(edge_dirs_at(p, wires));
|
||||
self.tracking_dirs.push(dirs);
|
||||
}
|
||||
|
||||
/// If the cursor dwelt on a snap point long enough but the in-place check
|
||||
@@ -341,7 +355,13 @@ impl Snapper {
|
||||
/// is only re-examined once the cursor moves off), acquire it now as the
|
||||
/// cursor leaves. This makes "pause on a corner, then drag along its edge"
|
||||
/// reliably capture the corner (#219).
|
||||
fn acquire_on_leave(&mut self, now: Instant, dwell_ms: u128, wires: &[WireModel]) {
|
||||
fn acquire_on_leave(
|
||||
&mut self,
|
||||
now: Instant,
|
||||
dwell_ms: u128,
|
||||
wires: &[WireModel],
|
||||
endpoints_only: bool,
|
||||
) {
|
||||
if self.dwell_acquired {
|
||||
return; // already handled by the in-place branch
|
||||
}
|
||||
@@ -352,7 +372,7 @@ impl Snapper {
|
||||
.dwell_since
|
||||
.map_or(0, |t| now.duration_since(t).as_millis());
|
||||
if elapsed >= dwell_ms {
|
||||
self.acquire_tracking_point(prev, wires);
|
||||
self.acquire_tracking_point(prev, wires, endpoints_only);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1547,4 +1567,28 @@ mod ext_tests {
|
||||
s.tracking_points.push(Vec3::new(big as f32, 0.0, 0.0));
|
||||
assert!(s.is_tracked_endpoint(glam::DVec3::new(big, 0.0, 0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extension_acquisition_keeps_only_endpoints() {
|
||||
let mut s = Snapper::default();
|
||||
// A single line segment (0,0)-(10,0): its endpoints are vertices, its
|
||||
// midpoint and any extension foot are not.
|
||||
let wire = WireModel {
|
||||
points: vec![[0.0, 0.0, 0.0], [10.0, 0.0, 0.0]],
|
||||
..Default::default()
|
||||
};
|
||||
let wires = [wire];
|
||||
|
||||
// Extension-driven acquisition (endpoints_only): a midpoint — like an
|
||||
// extension foot the cursor paused on — is ignored, so it can't fill the
|
||||
// buffer and evict the real endpoint (#262).
|
||||
s.acquire_tracking_point(Vec3::new(5.0, 0.0, 0.0), &wires, true);
|
||||
assert!(s.tracking_points.is_empty());
|
||||
// The genuine endpoint is acquired.
|
||||
s.acquire_tracking_point(Vec3::new(10.0, 0.0, 0.0), &wires, true);
|
||||
assert_eq!(s.tracking_points.len(), 1);
|
||||
// OTRACK (endpoints_only = false) still acquires any snap point.
|
||||
s.acquire_tracking_point(Vec3::new(5.0, 0.0, 0.0), &wires, false);
|
||||
assert_eq!(s.tracking_points.len(), 2);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user