fix(ucs): object snap tracking rays follow the active UCS
OTRACK alignment rays (0°/90° and polar steps, plus the polar pencil from the last point) were built along world X/Y. They now rotate with the active UCS via a Mat4 passed into otrack_snap (scene.viewcube_ucs_mat() — the UCS in model space, identity in paper), so tracking lines and the intersection lock align to the user's coordinate system like ortho, polar, and the grid. sync_ucs_to_scene now reuses UcsXform::rotation_mat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
98142ee4af
commit
2509396ba0
4 changed files with 21 additions and 10 deletions
|
|
@ -192,13 +192,7 @@ impl DocumentTab {
|
||||||
/// Push the active UCS rotation into the scene so the ViewCube composes with
|
/// Push the active UCS rotation into the scene so the ViewCube composes with
|
||||||
/// it. Call after any change to `active_ucs`.
|
/// it. Call after any change to `active_ucs`.
|
||||||
pub(super) fn sync_ucs_to_scene(&mut self) {
|
pub(super) fn sync_ucs_to_scene(&mut self) {
|
||||||
let (_, x, y, z) = self.ucs_xform().axes();
|
self.scene.viewcube_ucs = self.ucs_xform().rotation_mat();
|
||||||
self.scene.viewcube_ucs = glam::Mat4::from_cols(
|
|
||||||
x.extend(0.0),
|
|
||||||
y.extend(0.0),
|
|
||||||
z.extend(0.0),
|
|
||||||
glam::Vec4::W,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn new_drawing(n: usize) -> Self {
|
pub(super) fn new_drawing(n: usize) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,17 @@ impl UcsXform {
|
||||||
pub(super) fn axes(&self) -> (glam::Vec3, glam::Vec3, glam::Vec3, glam::Vec3) {
|
pub(super) fn axes(&self) -> (glam::Vec3, glam::Vec3, glam::Vec3, glam::Vec3) {
|
||||||
(self.origin, self.x, self.y, self.z)
|
(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`) ────────────────────
|
// ── UCS ↔ WCS transforms (thin wrappers over `UcsXform`) ────────────────────
|
||||||
|
|
|
||||||
|
|
@ -2839,12 +2839,14 @@ impl OpenCADStudio {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let ucs = self.tabs[i].scene.viewcube_ucs_mat();
|
||||||
self.snapper.otrack_snap(
|
self.snapper.otrack_snap(
|
||||||
cursor_world,
|
cursor_world,
|
||||||
view_proj,
|
view_proj,
|
||||||
bounds,
|
bounds,
|
||||||
step,
|
step,
|
||||||
self.last_point,
|
self.last_point,
|
||||||
|
ucs,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -3464,8 +3466,9 @@ impl OpenCADStudio {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let ucs = self.tabs[i].scene.viewcube_ucs_mat();
|
||||||
self.snapper
|
self.snapper
|
||||||
.otrack_snap(raw, vp_mat, bounds, step, self.last_point)
|
.otrack_snap(raw, vp_mat, bounds, step, self.last_point, ucs)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,9 @@ impl Snapper {
|
||||||
bounds: iced::Rectangle,
|
bounds: iced::Rectangle,
|
||||||
polar_step_deg: Option<f32>,
|
polar_step_deg: Option<f32>,
|
||||||
last_point: Option<Vec3>,
|
last_point: Option<Vec3>,
|
||||||
|
// UCS→world rotation: tracking rays run along the UCS axes, matching
|
||||||
|
// ortho/polar. Identity = world-aligned rays.
|
||||||
|
ucs: glam::Mat4,
|
||||||
) -> Option<OtrackHit> {
|
) -> Option<OtrackHit> {
|
||||||
if !self.otrack_enabled || self.tracking_points.is_empty() {
|
if !self.otrack_enabled || self.tracking_points.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -307,7 +310,7 @@ impl Snapper {
|
||||||
let ar = adeg.to_radians();
|
let ar = adeg.to_radians();
|
||||||
rays.push(Ray {
|
rays.push(Ray {
|
||||||
origin: tp,
|
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,
|
group: gi,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +325,7 @@ impl Snapper {
|
||||||
let ar = a.to_radians();
|
let ar = a.to_radians();
|
||||||
rays.push(Ray {
|
rays.push(Ray {
|
||||||
origin: lp,
|
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,
|
group: POLAR_GROUP,
|
||||||
});
|
});
|
||||||
a += step;
|
a += step;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue