forked from 1b-agent/opencadstudio-upstream
ucs: a click at the option prompt sets the origin, with axis preview
UCS waited for an option keyword before taking any point. A picked or typed point at the first prompt now starts the origin / X / XY placement directly. A live L of the new X and Y axes follows the cursor, and Enter accepts what has been placed so far: the origin alone moves the UCS, an X point turns it about the current Z. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
889e30019b
commit
b28a3d0b7b
1 file changed
+57
-2
@@ -8,7 +8,8 @@
|
||||
//! via [`CmdResult::Dispatch`], so the coordinate-system math and persistence
|
||||
//! stay in one place. (#169)
|
||||
|
||||
use crate::command::{CadCommand, CmdResult};
|
||||
use crate::command::{CadCommand, CmdResult, WorkingPlane};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
use crate::t;
|
||||
use glam::DVec3;
|
||||
|
||||
@@ -17,6 +18,7 @@ pub struct UcsCommand {
|
||||
/// The chosen option keyword (uppercased), once entered; `None` until then.
|
||||
option: Option<String>,
|
||||
points: Vec<DVec3>,
|
||||
plane: WorkingPlane,
|
||||
}
|
||||
|
||||
impl UcsCommand {
|
||||
@@ -79,9 +81,39 @@ impl CadCommand for UcsCommand {
|
||||
true
|
||||
}
|
||||
|
||||
fn set_working_plane(&mut self, plane: WorkingPlane) {
|
||||
self.plane = plane;
|
||||
}
|
||||
|
||||
/// The new X and Y axes, drawn from the origin while the 3-point UCS is
|
||||
/// being placed.
|
||||
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> {
|
||||
if !matches!(self.option.as_deref(), Some("3POINT") | Some("3P")) {
|
||||
return None;
|
||||
}
|
||||
let (origin, x, y) = match self.points.as_slice() {
|
||||
[origin] => (*origin, pt - *origin, self.plane.z.cross(pt - *origin)),
|
||||
[origin, on_x] => {
|
||||
let x = *on_x - *origin;
|
||||
let d = pt - *origin;
|
||||
(*origin, x, d - x * (d.dot(x) / x.length_squared().max(1.0e-300)))
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let y = y.normalize_or_zero() * x.length();
|
||||
if y == DVec3::ZERO {
|
||||
return None;
|
||||
}
|
||||
let corner = [origin + x, origin, origin + y].map(|p| p.to_array());
|
||||
let (points, points_low) = crate::scene::convert::tessellate::points_to_ds(corner);
|
||||
let mut wire = WireModel::solid("ucs_preview".into(), points, WireModel::CYAN, false);
|
||||
wire.points_low = points_low;
|
||||
Some(wire)
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
let t = text.trim();
|
||||
if matches!(self.option.as_deref(), Some("3POINT") | Some("3P"))
|
||||
if matches!(self.option.as_deref(), None | Some("3POINT") | Some("3P"))
|
||||
&& crate::app::helpers::parse_coord(t).is_some()
|
||||
{
|
||||
return None;
|
||||
@@ -111,6 +143,11 @@ impl CadCommand for UcsCommand {
|
||||
}
|
||||
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
// A click at the option prompt is the new origin; the X axis and XY
|
||||
// plane points follow, each optional.
|
||||
if self.option.is_none() {
|
||||
self.option = Some("3P".into());
|
||||
}
|
||||
if matches!(self.option.as_deref(), Some("3POINT") | Some("3P")) {
|
||||
self.points.push(pt);
|
||||
if self.points.len() < 3 {
|
||||
@@ -141,9 +178,27 @@ impl CadCommand for UcsCommand {
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
let points = std::mem::take(&mut self.points);
|
||||
match self.option.take() {
|
||||
// No option chosen yet → behave like bare `UCS` (list).
|
||||
None => CmdResult::Dispatch("UCS LIST".into()),
|
||||
// Enter accepts the axes placed so far: the origin alone moves the
|
||||
// UCS, an X point turns it about its current Z.
|
||||
Some(opt) if matches!(opt.as_str(), "3POINT" | "3P") && !points.is_empty() => {
|
||||
let origin = points[0];
|
||||
let Some(&on_x) = points.get(1) else {
|
||||
return CmdResult::Dispatch(format!(
|
||||
"UCS ORIGINW {},{},{}",
|
||||
origin.x, origin.y, origin.z
|
||||
));
|
||||
};
|
||||
let y = self.plane.z.cross(on_x - origin);
|
||||
let on_xy = origin + if y == DVec3::ZERO { self.plane.y } else { y };
|
||||
CmdResult::Dispatch(format!(
|
||||
"UCS 3POINTW {},{},{}|{},{},{}|{},{},{}",
|
||||
origin.x, origin.y, origin.z, on_x.x, on_x.y, on_x.z, on_xy.x, on_xy.y, on_xy.z,
|
||||
))
|
||||
}
|
||||
// Option chosen but no value supplied → cancel cleanly.
|
||||
Some(_) => CmdResult::Cancel,
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user