feat(ucs): integrate coordinate systems

Route coordinate input, geometry creation, transforms, properties,\nviews, and viewport persistence through a shared working plane.\n\nRefs #484
This commit is contained in:
Hakan Seven committed 2026-08-04 23:17:54 +03:00
1 parent b1d55c6a7e
commit 657d023fb7
61 files changed
+2218 -747

No files matched your search

+25 -32
View File
@@ -257,11 +257,22 @@ impl DocumentTab {
/// is identity (plain WCS).
pub(super) fn model_ucs_from_header(&self) -> Option<Ucs> {
let h = &self.scene.document.header;
let mut u = Ucs::new(h.model_space_ucs_name.clone());
let mut u = if h.model_space_ucs_name.is_empty() {
Ucs::new("*ACTIVE*")
} else {
self.scene
.document
.ucss
.get(&h.model_space_ucs_name)
.cloned()
.unwrap_or_else(|| Ucs::new(h.model_space_ucs_name.clone()))
};
u.origin = h.model_space_ucs_origin;
u.x_axis = h.model_space_ucs_x_axis;
u.y_axis = h.model_space_ucs_y_axis;
if super::helpers::UcsXform::from_ucs(&u).is_identity() {
if h.model_space_ucs_name.is_empty()
&& super::helpers::UcsXform::from_ucs(&u).is_identity()
{
None
} else {
Some(u)
@@ -278,11 +289,21 @@ impl DocumentTab {
if !vp.ucs_per_viewport {
return None;
}
let mut u = Ucs::new("*VPUCS*");
let mut u = if vp.ucs_handle.is_null() {
Ucs::new("*VPUCS*")
} else {
self.scene
.document
.ucss
.iter()
.find(|ucs| ucs.handle == vp.ucs_handle)
.cloned()
.unwrap_or_else(|| Ucs::new("*VPUCS*"))
};
u.origin = vp.ucs_origin;
u.x_axis = vp.ucs_x_axis;
u.y_axis = vp.ucs_y_axis;
if super::helpers::UcsXform::from_ucs(&u).is_identity() {
if vp.ucs_handle.is_null() && super::helpers::UcsXform::from_ucs(&u).is_identity() {
None
} else {
Some(u)
@@ -369,34 +390,6 @@ impl DocumentTab {
self.scene.viewcube_ucs = self.ucs_xform().rotation_mat();
}
/// UCS→render(wire)-space affine for commands that build axis-aligned
/// geometry. Columns are the UCS axes; translation is the UCS origin in wire
/// space. Identity outside model space (no UCS there).
pub(super) fn ucs_wire_affine(&self) -> glam::Mat4 {
if !self.editing_model_space() {
return glam::Mat4::IDENTITY;
}
let (o, x, y, z) = self.ucs_xform().axes();
let origin = glam::Vec3::new(o.x as f32, o.y as f32, o.z as f32);
glam::Mat4::from_cols(
x.as_vec3().extend(0.0),
y.as_vec3().extend(0.0),
z.as_vec3().extend(0.0),
origin.extend(1.0),
)
}
/// World-space rotation angle (radians) of the active UCS X axis — the
/// default rotation for new text-bearing objects so their text aligns to
/// the user's coordinate system. Zero outside model space / with no UCS.
pub(super) fn ucs_rotation_angle(&self) -> f64 {
if !self.editing_model_space() {
return 0.0;
}
let (_, x, ..) = self.ucs_xform().axes();
(x.y as f64).atan2(x.x as f64)
}
/// Grid origin (render/wire space) and UCS→world rotation for grid snap and
/// the grid overlay. Identity / origin-at-zero outside model space.
pub(super) fn ucs_grid_basis(&self) -> (glam::Vec3, glam::Mat4) {