fix(precision): keep typed coordinates exact in f64 (#311)

Typed values were quantized to the f32 grid before reaching the
entity (e.g. a length of 2000.8 committed as 2000.8020), worsening
with magnitude. The interaction point layer was all glam::Vec3 (f32).

Two-layer fix:

1. Coordinate backbone -> f64. last_point, last_cursor_world,
   dyn_anchor, dyn_ref become DVec3; UcsXform transforms, parse_coord,
   the ucs helper fns, dyn_resolve_point, the OTRACK typed-distance
   paths, command-line coordinate entry and the coordinate readout all
   compute in f64. Screen/GPU/alignment stays f32 (snap engine, render
   geometry, projection, UCS-icon/viewcube drawing) with casts only at
   those boundaries.

2. Per-command committed storage -> DVec3. on_point already received a
   DVec3, but many command impls narrowed it back to f32 (let pt =
   pt.as_vec3(); Vec<Vec3> fields) and re-widened at build, quantizing
   the committed coordinate. Migrated PLINE, SPLINE, MLINE, LENGTHEN,
   INSERT, 3D primitives, every dimension/leader/mleader, ray, revcloud,
   wipeout, attdef, table, tolerance, array center, mview, plot_window,
   plus the QDIM_PLACE handler and qdim_collect_points. Preview,
   hit-test and rubber-band paths keep f32 at the boundary.

Hatch manual boundaries are left for a follow-up: HatchModel.boundary
is structurally Arc<Vec<[f32;2]>> and needs a model-level widen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-11 21:26:40 +03:00
1 parent 8ed10ceb2a
commit 57710eec2b
47 files changed
+699 -606

No files matched your search

+21 -16
View File
@@ -159,11 +159,16 @@ pub fn lengthen_entity(entity: &EntityType, pick_pt: Vec3, mode: &LenMode) -> Op
}
fn lengthen_line(line: &LineEnt, pick_pt: Vec3, mode: &LenMode) -> Option<EntityType> {
let s = Vec3::new(line.start.x as f32, line.start.y as f32, 0.0);
let e = Vec3::new(line.end.x as f32, line.end.y as f32, 0.0);
let p = Vec3::new(pick_pt.x, pick_pt.y, 0.0);
// Keep the line's own coordinates on the f64 grid; only pick_pt (screen-only,
// nearest-end selection) widens for the distance compare.
let sx = line.start.x;
let sy = line.start.y;
let ex = line.end.x;
let ey = line.end.y;
let current_len = (e - s).length() as f64;
let dx = ex - sx;
let dy = ey - sy;
let current_len = (dx * dx + dy * dy).sqrt();
if current_len < 1e-10 {
return None;
}
@@ -173,23 +178,28 @@ fn lengthen_line(line: &LineEnt, pick_pt: Vec3, mode: &LenMode) -> Option<Entity
return None;
}
let dir = (e - s) / current_len as f32;
let ux = dx / current_len;
let uy = dy / current_len;
// Which end is closer to pick?
let dist_to_start = (p - s).length();
let dist_to_end = (p - e).length();
let px = pick_pt.x as f64;
let py = pick_pt.y as f64;
let dist_to_start = (px - sx).hypot(py - sy);
let dist_to_end = (px - ex).hypot(py - ey);
let mut result = line.clone();
result.common.handle = Handle::NULL;
if dist_to_end <= dist_to_start {
// Extend/trim the end
let new_end = s + dir * new_len as f32;
result.end = xz_to_v3(new_end, line.end.z);
let new_x = sx + ux * new_len;
let new_y = sy + uy * new_len;
result.end = Vector3::new(new_x, new_y, line.end.z);
} else {
// Extend/trim the start (move start backward along dir)
let new_start = e - dir * new_len as f32;
result.start = xz_to_v3(new_start, line.start.z);
let new_x = ex - ux * new_len;
let new_y = ey - uy * new_len;
result.start = Vector3::new(new_x, new_y, line.start.z);
}
Some(EntityType::Line(result))
}
@@ -335,11 +345,6 @@ fn arc_span_rad(start: f64, end: f64) -> f64 {
}
}
fn xz_to_v3(v: Vec3, z: f64) -> Vector3 {
// v is (world_x, world_z, 0) → DXF (x, world_z, z)
Vector3::new(v.x as f64, v.y as f64, z)
}
fn lengthen_lwpoly(poly: &LwPolyline, pick_pt: Vec3, mode: &LenMode) -> Option<EntityType> {
let n = poly.vertices.len();
if n < 2 {