feat(input): relative coordinate entry (@/#) and DYN default — #26

Koordinat girişi artık göreli/mutlak ayrımını destekliyor:
- `@x,y[,z]` → son girilen noktaya göreli (UCS eksenlerinde döndürülür)
- `#x,y[,z]` → her zaman mutlak (DYN durumundan bağımsız)
- ön ek yok → DYN açıksa göreli, kapalıysa mutlak
İlk noktada referans olmadığından göreli giriş mutlağa düşer. Çözülen
WCS noktası last_point olarak saklanıyor, böylece ardışık göreli
girişler zincirleniyor.

parse_coord artık (Vec3, CoordKind) döndürüyor; relative offset için
ucs_rotate_vec eklendi (origin translation olmadan UCS rotasyonu).
UCS ORIGIN komutu prefix'i yok sayıp mutlak kalıyor.

Ayrıca ViewCube snap refactor'undan kalan kullanılmayan kod temizlendi:
angle_close, active_viewport_yaw_pitch, CubeRegion::snap_angles.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-05-27 11:40:28 +03:00
commit 874226bd43
5 changed files with 77 additions and 81 deletions

View file

@ -1,5 +1,6 @@
use super::helpers::{
angle_close, ortho_constrain, parse_coord, polar_constrain, ucs_to_wcs, ucs_z_axis,
ortho_constrain, parse_coord, polar_constrain, ucs_rotate_vec, ucs_to_wcs, ucs_z_axis,
CoordKind,
};
use super::{Message, OpenCADStudio, POLY_START_DELAY_MS};
use crate::modules::ModuleEvent;
@ -960,13 +961,40 @@ impl OpenCADStudio {
return Task::none();
}
if let Some(ucs_pt) = parse_coord(&text) {
// Typed coordinates are in active UCS space; convert to WCS.
let wcs_pt = if let Some(ref ucs) = self.tabs[i].active_ucs {
ucs_to_wcs(ucs_pt, ucs)
} else {
ucs_pt
if let Some((coord, kind)) = parse_coord(&text) {
// Resolve relative vs absolute. `@` forces relative,
// `#` forces absolute, no prefix follows DYN: when
// dynamic input is on, bare coordinates are relative
// to the last point (issue #26).
// `@` forces relative, `#` forces absolute, no
// prefix follows DYN (on → relative). The very
// first point has no reference, so relative falls
// back to absolute.
let want_relative = match kind {
CoordKind::Relative => true,
CoordKind::Absolute => false,
CoordKind::Default => self.dyn_input,
};
let ucs = self.tabs[i].active_ucs.clone();
let wcs_pt = match (want_relative, self.last_point) {
(true, Some(base)) => {
// Offset from the last point, rotated by the
// UCS axes (no origin translation).
let offset = match &ucs {
Some(u) => ucs_rotate_vec(coord, u),
None => coord,
};
base + offset
}
_ => {
// Absolute: typed coordinates are in active UCS.
match &ucs {
Some(u) => ucs_to_wcs(coord, u),
None => coord,
}
}
};
self.last_point = Some(wcs_pt);
let result = self.tabs[i].active_cmd.as_mut().map(|c| c.on_point(wcs_pt));
if let Some(r) = result {
return self.apply_cmd_result(r);