forked from 1b-agent/opencadstudio-upstream
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:
1 parent
b1d55c6a7e
commit
657d023fb7
61 files changed
+2218
-747
No files matched your search
@@ -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();
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user