mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-25 19:36:49 -06:00
STRETCH gets its own prompt machine instead of a special case inside the shared MOVE/ROTATE/SCALE one. "Select objects" now repeats until Enter: implied windows (crossing right to left), `C` and `W` windows, single picks and All/Last/Previous (moved whole), Remove/Add. Vertices inside any of the windows move. Enter or `Displacement` at the base point asks for a displacement, and Enter at the second point uses the base point as the displacement, as in AutoCAD. Polygon and fence selection say they are not available yet instead of being misread. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.6 KiB
Rust
70 lines
2.6 KiB
Rust
//! STRETCH: repeated crossing selections until Enter, the `C`/`W` selection keywords, and the
|
|
//! Displacement option (typed, or Enter at the base point prompt).
|
|
|
|
use cadcraft_engine::Session;
|
|
use cadcraft_engine::doc::EntityKind;
|
|
|
|
/// Every line as ((ax, ay), (bx, by)), sorted by the first x.
|
|
fn lines(s: &Session) -> Vec<((f64, f64), (f64, f64))> {
|
|
let mut v: Vec<_> = s
|
|
.doc()
|
|
.unwrap()
|
|
.model
|
|
.iter()
|
|
.filter_map(|e| if let EntityKind::Line(l) = &e.kind { Some(((l.a.x, l.a.y), (l.b.x, l.b.y))) } else { None })
|
|
.collect();
|
|
v.sort_by(|a, b| a.0.0.total_cmp(&b.0.0).then(a.0.1.total_cmp(&b.0.1)));
|
|
v
|
|
}
|
|
|
|
fn session_with_lines(lines: &[&str]) -> Session {
|
|
let mut s = Session::new();
|
|
for l in lines {
|
|
s.cmdline(&format!("LINE {l}")).unwrap();
|
|
s.cmdline("").unwrap();
|
|
}
|
|
s
|
|
}
|
|
|
|
#[test]
|
|
fn stretch_script_with_crossing_keyword() {
|
|
let mut s = session_with_lines(&["0,0 10,0"]);
|
|
s.script("STRETCH C 12,1 8,-1 0,0 5,0\n").unwrap();
|
|
assert!(s.running.is_none(), "{}", s.prompt_text());
|
|
assert_eq!(lines(&s), vec![((0.0, 0.0), (15.0, 0.0))]);
|
|
}
|
|
|
|
#[test]
|
|
fn stretch_keeps_selecting_until_enter() {
|
|
let mut s = session_with_lines(&["0,0 10,0", "0,5 10,5"]);
|
|
// Two implied crossing windows (right to left), each around one right-hand end.
|
|
s.cmdline("STRETCH").unwrap();
|
|
for t in ["12,1", "8,-1", "12,6", "8,4", ""] {
|
|
s.cmdline(t).unwrap();
|
|
}
|
|
assert!(s.prompt_text().contains("base point"), "{}", s.prompt_text());
|
|
s.cmdline("0,0").unwrap();
|
|
s.cmdline("0,2").unwrap();
|
|
assert!(s.running.is_none());
|
|
assert_eq!(lines(&s), vec![((0.0, 0.0), (10.0, 2.0)), ((0.0, 5.0), (10.0, 7.0))]);
|
|
}
|
|
|
|
#[test]
|
|
fn stretch_displacement_option() {
|
|
// Enter at the base point prompt asks for a displacement.
|
|
let mut s = session_with_lines(&["0,0 10,0"]);
|
|
s.script("STRETCH C 12,1 8,-1\n\n\n3,4\n").unwrap();
|
|
assert!(s.running.is_none(), "{}", s.prompt_text());
|
|
assert_eq!(lines(&s), vec![((0.0, 0.0), (13.0, 4.0))]);
|
|
// The Displacement keyword does the same.
|
|
let mut s = session_with_lines(&["0,0 10,0"]);
|
|
s.script("STRETCH C 12,1 8,-1 D 3,4\n").unwrap();
|
|
assert!(s.running.is_none(), "{}", s.prompt_text());
|
|
assert_eq!(lines(&s), vec![((0.0, 0.0), (13.0, 4.0))]);
|
|
// Enter at the second point uses the base point as the displacement.
|
|
let mut s = session_with_lines(&["0,0 10,0"]);
|
|
s.script("STRETCH C 12,1 8,-1 2,0\n\n").unwrap();
|
|
assert!(s.running.is_none(), "{}", s.prompt_text());
|
|
assert_eq!(lines(&s), vec![((0.0, 0.0), (12.0, 0.0))]);
|
|
}
|