diff --git a/src/app/document.rs b/src/app/document.rs index c3471310d..288377ac2 100644 --- a/src/app/document.rs +++ b/src/app/document.rs @@ -192,13 +192,7 @@ impl DocumentTab { /// Push the active UCS rotation into the scene so the ViewCube composes with /// it. Call after any change to `active_ucs`. pub(super) fn sync_ucs_to_scene(&mut self) { - let (_, x, y, z) = self.ucs_xform().axes(); - self.scene.viewcube_ucs = glam::Mat4::from_cols( - x.extend(0.0), - y.extend(0.0), - z.extend(0.0), - glam::Vec4::W, - ); + self.scene.viewcube_ucs = self.ucs_xform().rotation_mat(); } pub(super) fn new_drawing(n: usize) -> Self { diff --git a/src/app/helpers.rs b/src/app/helpers.rs index 4af495a81..a63e1c336 100644 --- a/src/app/helpers.rs +++ b/src/app/helpers.rs @@ -118,6 +118,17 @@ impl UcsXform { pub(super) fn axes(&self) -> (glam::Vec3, glam::Vec3, glam::Vec3, glam::Vec3) { (self.origin, self.x, self.y, self.z) } + + /// UCS→world rotation matrix (columns = UCS axes). For consumers that take + /// a `Mat4` rotation directly (ViewCube, OTRACK ray directions). + pub(super) fn rotation_mat(&self) -> glam::Mat4 { + glam::Mat4::from_cols( + self.x.extend(0.0), + self.y.extend(0.0), + self.z.extend(0.0), + glam::Vec4::W, + ) + } } // ── UCS ↔ WCS transforms (thin wrappers over `UcsXform`) ──────────────────── diff --git a/src/app/update.rs b/src/app/update.rs index d7f9ef32d..7601d8fd7 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -2839,12 +2839,14 @@ impl OpenCADStudio { } else { None }; + let ucs = self.tabs[i].scene.viewcube_ucs_mat(); self.snapper.otrack_snap( cursor_world, view_proj, bounds, step, self.last_point, + ucs, ) } else { None @@ -3464,8 +3466,9 @@ impl OpenCADStudio { } else { None }; + let ucs = self.tabs[i].scene.viewcube_ucs_mat(); self.snapper - .otrack_snap(raw, vp_mat, bounds, step, self.last_point) + .otrack_snap(raw, vp_mat, bounds, step, self.last_point, ucs) } else { None }; diff --git a/src/snap/mod.rs b/src/snap/mod.rs index f5d82e4f3..641bfefab 100644 --- a/src/snap/mod.rs +++ b/src/snap/mod.rs @@ -263,6 +263,9 @@ impl Snapper { bounds: iced::Rectangle, polar_step_deg: Option, last_point: Option, + // UCS→world rotation: tracking rays run along the UCS axes, matching + // ortho/polar. Identity = world-aligned rays. + ucs: glam::Mat4, ) -> Option { if !self.otrack_enabled || self.tracking_points.is_empty() { return None; @@ -307,7 +310,7 @@ impl Snapper { let ar = adeg.to_radians(); rays.push(Ray { origin: tp, - dir: Vec3::new(ar.cos(), ar.sin(), 0.0), + dir: ucs.transform_vector3(Vec3::new(ar.cos(), ar.sin(), 0.0)), group: gi, }); } @@ -322,7 +325,7 @@ impl Snapper { let ar = a.to_radians(); rays.push(Ray { origin: lp, - dir: Vec3::new(ar.cos(), ar.sin(), 0.0), + dir: ucs.transform_vector3(Vec3::new(ar.cos(), ar.sin(), 0.0)), group: POLAR_GROUP, }); a += step;