From 5b1a5a71a034fd84ca90a0af5f9540a1b856f440 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 24 Jun 2026 18:41:25 +0300 Subject: [PATCH] refactor: finish OST f64 integration; drop vestigial _f64 suffixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Object-snap-tracking points now project through the relative-to-eye path (view_proj_rte + eye) instead of the full view-projection, so they stay precise at UTM-scale coordinates — the last consumer of the legacy full view_proj outside the CPU frustum-cull / scissor path. - Rename Camera::project_f64 → project and unproject_on_plane_f64 → unproject_on_plane: the f32 twins are gone, so the disambiguating suffix is vestigial. eye_f64 keeps its name — the f32 eye() still builds the view matrices. - Remove stale #[allow(dead_code)] from eye_f64 / project / unproject_on_plane (all live now). Co-Authored-By: Claude Opus 4.8 --- src/app/view.rs | 11 ++++++++--- src/scene/pick/grip.rs | 6 +++--- src/scene/view/camera.rs | 11 ++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/app/view.rs b/src/app/view.rs index adf2c635..6ae90331 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -221,14 +221,19 @@ impl OpenCADStudio { None }; - // OST tracking points → screen positions. + // OST tracking points → screen positions, projected relative-to-eye + // so they stay precise at UTM-scale coordinates (the full + // view-projection cancels catastrophically in f32). let ost_points: Vec = if self.snapper.otrack_enabled { - let vp_mat = tab.scene.camera.borrow().view_proj(vp_bounds); + let (view_rot, eye) = { + let cam = tab.scene.camera.borrow(); + (cam.view_proj_rte(vp_bounds), cam.eye_f64()) + }; self.snapper .tracking_points .iter() .map(|&wp| { - let ndc = vp_mat.project_point3(wp); + let ndc = view_rot.project_point3((wp.as_dvec3() - eye).as_vec3()); overlay::OstTrackPoint { screen: iced::Point::new( (ndc.x + 1.0) * 0.5 * vp_bounds.width, diff --git a/src/scene/pick/grip.rs b/src/scene/pick/grip.rs index 75561eaa..8f03ab74 100644 --- a/src/scene/pick/grip.rs +++ b/src/scene/pick/grip.rs @@ -43,7 +43,7 @@ pub fn grips_to_screen( // Project from the f64 grip position via the relative-to-eye path so // the grip stays glued to the wire at UTM-scale coordinates (an // `as_vec3` cast first would quantize it ~0.5 m off at high zoom). - let screen = match camera.project_f64(g.world, bounds) { + let screen = match camera.project(g.world, bounds) { Some(p) => Point::new(bounds.x + p.x, bounds.y + p.y), None => Point::new(f32::NAN, f32::NAN), }; @@ -115,7 +115,7 @@ pub fn find_hit_grip( let mut best: Option<(usize, bool, DVec3)> = None; for g in grips { - let Some(screen) = camera.project_f64(g.world, bounds) else { + let Some(screen) = camera.project(g.world, bounds) else { continue; }; let screen = Point::new(screen.x, screen.y); @@ -131,7 +131,7 @@ pub fn find_hit_grip( } /// Project an f64 world point with an explicit relative-to-eye `(view_rot, -/// eye)` pair — the camera-less form of `Camera::project_f64`. Used by the +/// eye)` pair — the camera-less form of `Camera::project`. Used by the /// in-viewport editing path, which supplies a *composed* model→screen view /// (see `Scene::composed_viewport_view`) instead of a real camera. fn project_rte(world: DVec3, view_rot: Mat4, eye: DVec3, bounds: Rectangle) -> Option { diff --git a/src/scene/view/camera.rs b/src/scene/view/camera.rs index dedb73ba..47f61499 100644 --- a/src/scene/view/camera.rs +++ b/src/scene/view/camera.rs @@ -79,7 +79,6 @@ impl Camera { /// Eye position in full f64 precision (offset-relative world space). Used /// by the relative-to-eye render path; the f32 [`eye`] stays for ray/pick /// math that operates at human scale. - #[allow(dead_code)] // consumed by the relative-to-eye uniform (next phase) pub fn eye_f64(&self) -> DVec3 { let eye_dir = (self.rotation * Vec3::Z).as_dvec3(); self.target + eye_dir * self.distance as f64 @@ -160,8 +159,7 @@ impl Camera { /// the rotation-only projection, so it stays exact at large absolute /// coordinates — the CPU equivalent of the GPU's relative-to-eye path. /// Returns `None` for points at/behind the eye plane (w ≈ 0). - #[allow(dead_code)] // consumed by the world_offset-removal CPU migration - pub fn project_f64(&self, p: glam::DVec3, bounds: Rectangle) -> Option { + pub fn project(&self, p: glam::DVec3, bounds: Rectangle) -> Option { let rel = (p - self.eye_f64()).as_vec3(); let clip = self.view_proj_rte(bounds) * rel.extend(1.0); if clip.w.abs() < 1e-9 { @@ -178,8 +176,7 @@ impl Camera { /// is built in eye-relative space (precise), intersected with the plane /// expressed relative to the eye, then shifted back by the f64 eye — so the /// returned world point keeps full precision at large absolute coordinates. - #[allow(dead_code)] // consumed by the world_offset-removal CPU migration - pub fn unproject_on_plane_f64( + pub fn unproject_on_plane( &self, screen: Point, bounds: Rectangle, @@ -242,13 +239,13 @@ impl Camera { plane_normal: Vec3, plane_point: glam::DVec3, ) -> glam::DVec3 { - self.unproject_on_plane_f64(screen, bounds, plane_normal, plane_point) + self.unproject_on_plane(screen, bounds, plane_normal, plane_point) } /// Project a screen point onto the plane through the orbit target. pub fn pick_on_target_plane(&self, screen: Point, bounds: Rectangle) -> glam::DVec3 { let forward = (self.target.as_vec3() - self.eye()).normalize_or(Vec3::NEG_Z); - self.unproject_on_plane_f64(screen, bounds, forward, self.target) + self.unproject_on_plane(screen, bounds, forward, self.target) }