fix(snap): f64-precise computed snaps + UTM-tolerant cull + f64 previews

Computed snaps (midpoint/nearest/perpendicular/intersection/extension/
apparent/grid) reconstructed the snap point from f32 `wire.points`
(absolute high half), so at UTM-scale they landed ~0.5 m off the geometry
while endpoint/center (sourced from f64 key_vertices/snap_pts) stayed
correct. Now they rebuild each vertex from points + points_low (the
double-single low residual) and run the geometry in f64:
- snap() cursor + geometry helpers (nearest_on_segment, perp_foot,
  seg_intersect_xy, extension_snap) are DVec3; wp_f64() reconstructs each
  vertex; midpoint uses f64 key_vertices directly (was downcast to f32).
- snap callers pass the precise DVec3 cursor.

Snap capture at deep zoom: the wire-AABB cull compared a sub-millimetre
snap radius against f32 bounds quantized by ~1 ulp (~0.7 m at 5.7e6),
wrongly excluding wires under the cursor. Pad the cull by the bound's own
f32 quantization so it never rejects an in-range wire.

Rubber-band previews (line/circle/arc/ellipse/rect/polygon) built f32
absolute points with an empty points_low, so the wire pass (relative-to-
eye) drew them ~0.5 m off the cursor at UTM. Add WireModel::solid_f64,
which splits f64 points into the double-single high/low pair; previews now
track the cursor exactly.

Known: snapping at extreme zoom on large drawings spikes CPU (per-move
snap cost) — deferred.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-24 04:26:05 +03:00
1 parent 4f7a98a2ad
commit bca8958025
8 files changed
+166 -158

No files matched your search

+3 -3
View File
@@ -2648,7 +2648,7 @@ impl OpenCADStudio {
self.snapper.from_point = None;
let (go, gr) = self.tabs[i].ucs_grid_basis();
let snap_hit =
self.snapper.snap(raw.as_vec3(), p, &all_wires[..], view_rot, eye, bounds, go, gr);
self.snapper.snap(raw, p, &all_wires[..], view_rot, eye, bounds, go, gr);
let mut snapped = 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() {
@@ -2827,7 +2827,7 @@ impl OpenCADStudio {
let (go, gr) = self.tabs[i].ucs_grid_basis();
self.snapper.from_point = self.last_point;
self.snapper
.snap(cursor_world.as_vec3(), p, &all_wires[..], view_rot, eye, bounds, go, gr)
.snap(cursor_world, p, &all_wires[..], view_rot, eye, bounds, go, gr)
};
// Object Snap Tracking: update dwell, then align the cursor
@@ -3464,7 +3464,7 @@ impl OpenCADStudio {
} else {
let (go, gr) = self.tabs[i].ucs_grid_basis();
self.snapper.from_point = self.last_point;
self.snapper.snap(raw.as_vec3(), p, &all_wires[..], view_rot, eye, bounds, go, gr)
self.snapper.snap(raw, p, &all_wires[..], view_rot, eye, bounds, go, gr)
};
// snap.world is in paper-space (projected wire coords in MSPACE);
// convert to model-space so commands receive consistent coordinates.