mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-25 19:36:49 -06:00
Stretching a grip now drags the grips of the other selected objects that sit on the same point, so connected lines stay connected, and the Move, Rotate, Scale and Mirror grip modes transform every selected object about the hot grip, as in AutoCAD. grip.move/grip.stretch take the other objects in `handles`; with only `handle` they edit that object alone, as before. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.4 KiB
Rust
61 lines
2.4 KiB
Rust
//! Grip editing acts on the whole selection, as in AutoCAD: a stretched grip drags the
|
|
//! coincident grips of the other selected objects with it, and Move/Rotate/Scale/Mirror
|
|
//! transform every selected object.
|
|
|
|
use cadcraft_engine::Session;
|
|
use cadcraft_engine::doc::{EntityKind, Handle};
|
|
use cadcraft_engine::geom::Vec2;
|
|
use cadcraft_engine::grips::GripMode;
|
|
use serde_json::json;
|
|
|
|
fn line(s: &mut Session, a: [f64; 2], b: [f64; 2]) -> Handle {
|
|
let r = s.execute("line", &json!({ "points": [a, b] })).unwrap();
|
|
Handle::parse_hex(r["handles"][0].as_str().unwrap()).unwrap()
|
|
}
|
|
|
|
fn ends(s: &Session, h: Handle) -> (Vec2, Vec2) {
|
|
match &s.doc().unwrap().entity(h).unwrap().kind {
|
|
EntityKind::Line(l) => (l.a.xy(), l.b.xy()),
|
|
k => panic!("not a line: {k:?}"),
|
|
}
|
|
}
|
|
|
|
fn near(p: Vec2, x: f64, y: f64) -> bool {
|
|
p.near(Vec2::new(x, y), 1e-9)
|
|
}
|
|
|
|
#[test]
|
|
fn grip_edits_act_on_the_selection() {
|
|
// Two connected lines and a third one elsewhere, all selected.
|
|
let mut s = Session::new();
|
|
let a = line(&mut s, [0.0, 0.0], [10.0, 0.0]);
|
|
let b = line(&mut s, [10.0, 0.0], [10.0, 10.0]);
|
|
let c = line(&mut s, [20.0, 0.0], [30.0, 0.0]);
|
|
s.set_selection(vec![a, b, c]);
|
|
let undo = s.state().unwrap().undo.len();
|
|
|
|
// Stretching the shared corner grip of `a` moves `b`'s start with it; `c` stays.
|
|
s.grip_edit(a, 2, Vec2::new(12.0, 3.0), GripMode::Stretch).unwrap();
|
|
assert!(near(ends(&s, a).1, 12.0, 3.0));
|
|
assert!(near(ends(&s, b).0, 12.0, 3.0) && near(ends(&s, b).1, 10.0, 10.0), "{:?}", ends(&s, b));
|
|
assert!(near(ends(&s, c).0, 20.0, 0.0) && near(ends(&s, c).1, 30.0, 0.0));
|
|
assert_eq!(s.state().unwrap().undo.len(), undo + 1, "one undo step");
|
|
|
|
// Move about a grip of `a`: every selected object moves.
|
|
s.grip_edit(a, 0, Vec2::new(1.0, 1.0), GripMode::Move).unwrap();
|
|
assert!(near(ends(&s, a).0, 1.0, 1.0));
|
|
assert!(near(ends(&s, b).1, 11.0, 11.0));
|
|
assert!(near(ends(&s, c).0, 21.0, 1.0));
|
|
|
|
// Rotate 90° about the same grip: `c` turns too.
|
|
s.grip_edit(a, 0, Vec2::new(1.0, 5.0), GripMode::Rotate).unwrap();
|
|
assert!(near(ends(&s, c).0, 1.0, 21.0), "{:?}", ends(&s, c));
|
|
|
|
// An object that isn't selected is only edited through its own grip.
|
|
s.set_selection(vec![a]);
|
|
let before = ends(&s, b);
|
|
let g = s.grips_of(a).unwrap()[2];
|
|
s.grip_edit(a, 2, g + Vec2::new(1.0, 0.0), GripMode::Stretch).unwrap();
|
|
assert_eq!(ends(&s, b), before);
|
|
}
|