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

+13 -5
View File
@@ -3,7 +3,7 @@
use glam::DVec3;
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::command::{CadCommand, CmdResult, WorkingPlane};
use crate::scene::model::wire_model::WireModel;
pub struct DistCommand {
@@ -11,15 +11,23 @@ pub struct DistCommand {
// loses ~0.03–0.06 units at survey-scale coordinates (e.g. eastings near
// 5e5), which made snapped-endpoint measurements read off by that much.
first: Option<DVec3>,
plane: WorkingPlane,
}
impl DistCommand {
pub fn new() -> Self {
Self { first: None }
Self {
first: None,
plane: WorkingPlane::default(),
}
}
}
impl CadCommand for DistCommand {
fn set_working_plane(&mut self, plane: WorkingPlane) {
self.plane = plane;
}
fn name(&self) -> &'static str {
"DIST"
}
@@ -34,11 +42,11 @@ impl CadCommand for DistCommand {
fn on_point(&mut self, pt: DVec3) -> CmdResult {
if let Some(p1) = self.first {
let delta = pt - p1;
let delta = self.plane.vector_to_local(pt - p1);
let dist = delta.length();
let dx = delta.x;
let dy = delta.y; // drawing plane is world XY
let dz = delta.z; // elevation
let dy = delta.y;
let dz = delta.z;
// Angle in XY plane — degrees from +X
let angle_xy = dy.atan2(dx).to_degrees();
+15 -7
View File
@@ -3,17 +3,25 @@
use glam::DVec3;
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::command::{CadCommand, CmdResult, WorkingPlane};
pub struct IdCommand;
pub struct IdCommand {
plane: WorkingPlane,
}
impl IdCommand {
pub fn new() -> Self {
Self
Self {
plane: WorkingPlane::default(),
}
}
}
impl CadCommand for IdCommand {
fn set_working_plane(&mut self, plane: WorkingPlane) {
self.plane = plane;
}
fn name(&self) -> &'static str {
"ID"
}
@@ -23,10 +31,10 @@ impl CadCommand for IdCommand {
}
fn on_point(&mut self, pt: DVec3) -> CmdResult {
// Drawing plane is world XY (z = elevation).
let x = pt.x;
let y = pt.y;
let z = pt.z;
let local = self.plane.to_local(pt);
let x = local.x;
let y = local.y;
let z = local.z;
let x_s = format!("{x:.4}");
let y_s = format!("{y:.4}");
let z_s = format!("{z:.4}");
+20 -7
View File
@@ -18,7 +18,7 @@ use acadrust::{EntityType, Handle};
use glam::DVec3;
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::command::{CadCommand, CmdResult, WorkingPlane};
use crate::modules::{IconKind, ModuleEvent, ToolDef};
use crate::scene::model::wire_model::WireModel;
@@ -54,6 +54,7 @@ pub struct MeasureGeomCommand {
points: Vec<DVec3>,
/// The picked entity for RADIUS, injected before `on_entity_pick`.
picked: Option<EntityType>,
plane: WorkingPlane,
}
impl MeasureGeomCommand {
@@ -62,6 +63,7 @@ impl MeasureGeomCommand {
mode: Mode::Choose,
points: vec![],
picked: None,
plane: WorkingPlane::default(),
}
}
@@ -107,12 +109,14 @@ impl MeasureGeomCommand {
}
/// DISTANCE readout for the two collected points.
fn distance_msg(p1: DVec3, p2: DVec3) -> String {
fn distance_msg(plane: WorkingPlane, p1: DVec3, p2: DVec3) -> String {
let p1 = plane.to_local(p1);
let p2 = plane.to_local(p2);
let delta = p2 - p1;
let dist = delta.length();
let dx = delta.x;
let dy = delta.y; // drawing plane is world XY
let dz = delta.z; // elevation
let dy = delta.y;
let dz = delta.z;
let angle_xy = dy.atan2(dx).to_degrees();
let dist_s = format!("{dist:.4}");
let angle_xy_s = format!("{angle_xy:.4}");
@@ -131,7 +135,8 @@ impl MeasureGeomCommand {
}
/// AREA readout: shoelace area (f64, relative to first vertex) + perimeter.
fn area_msg(points: &[DVec3]) -> String {
fn area_msg(plane: WorkingPlane, points: &[DVec3]) -> String {
let points = points.iter().map(|point| plane.to_local(*point)).collect::<Vec<_>>();
let n = points.len();
let origin = points[0];
let mut area_sum = 0.0f64;
@@ -207,6 +212,10 @@ impl CadCommand for MeasureGeomCommand {
}
}
fn set_working_plane(&mut self, plane: WorkingPlane) {
self.plane = plane;
}
fn wants_text_input(&self) -> bool {
// Only the opening mode-keyword step reads a typed token.
self.mode == Mode::Choose
@@ -267,7 +276,11 @@ impl CadCommand for MeasureGeomCommand {
Mode::Distance => {
self.points.push(pt);
if self.points.len() == 2 {
CmdResult::Measurement(Self::distance_msg(self.points[0], self.points[1]))
CmdResult::Measurement(Self::distance_msg(
self.plane,
self.points[0],
self.points[1],
))
} else {
CmdResult::NeedPoint
}
@@ -299,7 +312,7 @@ impl CadCommand for MeasureGeomCommand {
if self.points.len() < 3 {
CmdResult::Cancel
} else {
CmdResult::Measurement(Self::area_msg(&self.points))
CmdResult::Measurement(Self::area_msg(self.plane, &self.points))
}
}
_ => CmdResult::Cancel,