Files
OneCAD-Draft/src/modules/draw/inquiry/dist.rs
T
Hakan Seven 657d023fb7 feat(ucs): integrate coordinate systems
Route coordinate input, geometry creation, transforms, properties,\nviews, and viewport persistence through a shared working plane.\n\nRefs #484
2026-08-04 23:17:54 +03:00

124 lines
3.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// DIST command — measure distance and angle between two picked points.
use glam::DVec3;
use crate::t;
use crate::command::{CadCommand, CmdResult, WorkingPlane};
use crate::scene::model::wire_model::WireModel;
pub struct DistCommand {
// Keep the picked point in full f64 precision. Downcasting to f32 here
// 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,
plane: WorkingPlane::default(),
}
}
}
impl CadCommand for DistCommand {
fn set_working_plane(&mut self, plane: WorkingPlane) {
self.plane = plane;
}
fn name(&self) -> &'static str {
"DIST"
}
fn prompt(&self) -> String {
if self.first.is_none() {
t!("DIST Specify first point:").into_owned()
} else {
t!("DIST Specify second point:").into_owned()
}
}
fn on_point(&mut self, pt: DVec3) -> CmdResult {
if let Some(p1) = self.first {
let delta = self.plane.vector_to_local(pt - p1);
let dist = delta.length();
let dx = delta.x;
let dy = delta.y;
let dz = delta.z;
// Angle in XY plane — degrees from +X
let angle_xy = dy.atan2(dx).to_degrees();
// Angle from XY plane toward Z (elevation angle)
let dist_xy = dx.hypot(dy);
let angle_z = dz.atan2(dist_xy).to_degrees();
let dist_s = format!("{dist:.4}");
let angle_xy_s = format!("{angle_xy:.4}");
let angle_z_s = format!("{angle_z:.4}");
let dx_s = format!("{dx:.4}");
let dy_s = format!("{dy:.4}");
let dz_s = format!("{dz:.4}");
let msg = t!(
"Distance = %{dist}, Angle in XY Plane = %{angle_xy}°, Angle from XY Plane = %{angle_z}°\n Delta X = %{dx}, Delta Y = %{dy}, Delta Z = %{dz}",
dist = dist_s,
angle_xy = angle_xy_s,
angle_z = angle_z_s,
dx = dx_s,
dy = dy_s,
dz = dz_s,
)
.into_owned();
CmdResult::Measurement(msg)
} else {
self.first = Some(pt);
CmdResult::NeedPoint
}
}
fn on_enter(&mut self) -> CmdResult {
CmdResult::Cancel
}
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> {
let p1 = self.first?;
// The preview wire is purely visual, so f32 vertices are fine here.
Some(WireModel {
taper_widths: Vec::new(),
world_width: 0.0,
depth_override: None,
fill_is_3d: false,
fill_is_2d_solid: false,
pick_tris: Vec::new(),
pick_tris_low: Vec::new(),
dash_from_start: false,
dash_align_end: None,
text_verts: Vec::new(),
name: "dist_preview".into(),
points: vec![
[p1.x as f32, p1.y as f32, p1.z as f32],
[pt.x as f32, pt.y as f32, pt.z as f32],
],
points_low: Vec::new(),
color: WireModel::CYAN,
selected: false,
pattern_length: 0.0,
pattern: [0.0; 8],
line_weight_px: 1.0,
snap_pts: vec![],
tangent_geoms: vec![],
aci: 0,
key_vertices: vec![],
aabb: WireModel::UNBOUNDED_AABB,
plinegen: true,
fill_tris: vec![],
fill_tris_low: Vec::new(),
})
}
}
// ── Autocomplete registry ─────────────────────────────────
inventory::submit!(crate::command::CommandRegistration { names: &["DIST"] }); // DistCommand