Feat: implement WCS↔UCS coordinate transform pipeline
- Add `active_ucs: Option<Ucs>` per-tab state to DocumentTab - Add `ucs_to_wcs`, `wcs_to_ucs`, `ucs_z_axis`, `ucs_rotated_z` helpers - Add `Camera::pick_on_plane` for ray–plane intersection against any plane - Mouse picks project onto the active UCS XY plane instead of world XY - Typed coordinates are converted from UCS space to WCS before dispatch - UCS command now really activates/deactivates a UCS: - `UCS W` resets to WCS (clears active_ucs) - `UCS <name>` activates a named UCS - `UCS SAVE <name>` saves the current active UCS - `UCS ORIGIN x,y,z` shifts origin (in current UCS space) - `UCS X/Y/Z <angle>` rotates the UCS around its own axes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
98578cc5c0
commit
20629d587a
5 changed files with 270 additions and 24 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ui::overlay::GridPlane;
|
||||
use crate::scene::WireModel;
|
||||
use acadrust::tables::Ucs;
|
||||
|
||||
// ── Coordinate parsing ─────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -20,6 +21,50 @@ pub(super) fn parse_coord(text: &str) -> Option<glam::Vec3> {
|
|||
}
|
||||
}
|
||||
|
||||
// ── UCS ↔ WCS transforms ───────────────────────────────────────────────────
|
||||
|
||||
/// Convert a point from UCS local coordinates to WCS.
|
||||
///
|
||||
/// WCS = origin + x_axis*u + y_axis*v + z_axis*w
|
||||
pub(super) fn ucs_to_wcs(pt: glam::Vec3, ucs: &Ucs) -> glam::Vec3 {
|
||||
let o = glam::Vec3::new(ucs.origin.x as f32, ucs.origin.y as f32, ucs.origin.z as f32);
|
||||
let x = glam::Vec3::new(ucs.x_axis.x as f32, ucs.x_axis.y as f32, ucs.x_axis.z as f32);
|
||||
let y = glam::Vec3::new(ucs.y_axis.x as f32, ucs.y_axis.y as f32, ucs.y_axis.z as f32);
|
||||
let z_ax = ucs_z_axis(ucs);
|
||||
o + x * pt.x + y * pt.y + z_ax * pt.z
|
||||
}
|
||||
|
||||
/// Convert a WCS point back to UCS local coordinates.
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn wcs_to_ucs(pt: glam::Vec3, ucs: &Ucs) -> glam::Vec3 {
|
||||
let o = glam::Vec3::new(ucs.origin.x as f32, ucs.origin.y as f32, ucs.origin.z as f32);
|
||||
let x = glam::Vec3::new(ucs.x_axis.x as f32, ucs.x_axis.y as f32, ucs.x_axis.z as f32);
|
||||
let y = glam::Vec3::new(ucs.y_axis.x as f32, ucs.y_axis.y as f32, ucs.y_axis.z as f32);
|
||||
let z_ax = ucs_z_axis(ucs);
|
||||
let d = pt - o;
|
||||
glam::Vec3::new(d.dot(x), d.dot(y), d.dot(z_ax))
|
||||
}
|
||||
|
||||
/// Return the normalised Z axis of a UCS (cross product of X and Y axes).
|
||||
pub(super) fn ucs_z_axis(ucs: &Ucs) -> glam::Vec3 {
|
||||
let x = glam::Vec3::new(ucs.x_axis.x as f32, ucs.x_axis.y as f32, ucs.x_axis.z as f32);
|
||||
let y = glam::Vec3::new(ucs.y_axis.x as f32, ucs.y_axis.y as f32, ucs.y_axis.z as f32);
|
||||
x.cross(y).normalize_or_zero()
|
||||
}
|
||||
|
||||
/// Build a UCS with `origin` and axes rotated by `angle_z_rad` around the Z axis.
|
||||
pub(super) fn ucs_rotated_z(origin: glam::Vec3, angle_z: f32) -> Ucs {
|
||||
let cos = angle_z.cos() as f64;
|
||||
let sin = angle_z.sin() as f64;
|
||||
let mut ucs = Ucs::new("*ACTIVE*");
|
||||
ucs.origin = acadrust::types::Vector3::new(
|
||||
origin.x as f64, origin.y as f64, origin.z as f64,
|
||||
);
|
||||
ucs.x_axis = acadrust::types::Vector3::new(cos, sin, 0.0);
|
||||
ucs.y_axis = acadrust::types::Vector3::new(-sin, cos, 0.0);
|
||||
ucs
|
||||
}
|
||||
|
||||
pub(super) fn angle_close(a: f32, b: f32, tol: f32) -> bool {
|
||||
let diff = (a - b).rem_euclid(std::f32::consts::TAU);
|
||||
let diff = if diff > std::f32::consts::PI {
|
||||
|
|
|
|||
Loading…
Reference in a new issue