mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-24 10:27:00 -06:00
fix(engine): show the Pen's Shift 45° step in its preview line (#970)
A Shift-click with the Pen already put the next point at a 45° step from the last one, but the line drawn to the pointer while moving ignored Shift and followed the pointer, so holding Shift looked like it did nothing. The line now ends where the click will put the point. Both use one helper, at_45_degrees.
This commit is contained in:
@@ -63,3 +63,24 @@ fn finishing_the_path_clears_its_handles_and_band() {
|
|||||||
let ov = &s.tool.overlay;
|
let ov = &s.tool.overlay;
|
||||||
assert!(ov.pen.is_empty() && ov.pen_handles.is_empty() && ov.rubber.is_none() && ov.rubber_handle.is_none());
|
assert!(ov.pen.is_empty() && ov.pen_handles.is_empty() && ov.rubber.is_none() && ov.rubber_handle.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shift_keeps_the_band_and_the_next_point_at_45_degree_steps() {
|
||||||
|
// #970: with Shift the band shows where the point will land, at a 45° step from the last
|
||||||
|
// anchor (the same length as the pointer is away), not under the pointer.
|
||||||
|
let mut s = Session::new();
|
||||||
|
s.set_tool(ToolId::Pen);
|
||||||
|
at(&mut s, PointerKind::Down, 100.0, 100.0);
|
||||||
|
at(&mut s, PointerKind::Up, 100.0, 100.0);
|
||||||
|
let shifted = |kind, x, y| PointerEvent { shift: true, ..PointerEvent::at(kind, x, y, 1.0) };
|
||||||
|
s.pointer(&shifted(PointerKind::Hover, 300.0, 120.0)).unwrap();
|
||||||
|
let [x0, y0, x1, y1] = s.tool.overlay.rubber.unwrap();
|
||||||
|
assert_eq!([x0, y0, y1], [100.0, 100.0, 100.0], "level with the last anchor");
|
||||||
|
assert!((x1 - (100.0 + 200f64.hypot(20.0))).abs() < 1e-9, "{x1}");
|
||||||
|
s.pointer(&shifted(PointerKind::Down, 300.0, 120.0)).unwrap();
|
||||||
|
s.pointer(&shifted(PointerKind::Up, 300.0, 120.0)).unwrap();
|
||||||
|
s.pointer(&shifted(PointerKind::Hover, 400.0, 230.0)).unwrap();
|
||||||
|
let [x0, y0, x1, y1] = s.tool.overlay.rubber.unwrap();
|
||||||
|
assert_eq!(y0, 100.0, "the point landed on the band");
|
||||||
|
assert!((x1 - x0 - (y1 - y0)).abs() < 1e-9, "45° down to the right: {:?}", [x0, y0, x1, y1]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -413,6 +413,13 @@ pub(crate) enum Gesture {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Where Shift puts the Pen's next point: as far from `last` as `p` is, at the nearest 45° step.
|
||||||
|
fn at_45_degrees(last: Point, p: Point) -> Point {
|
||||||
|
let v = p - last;
|
||||||
|
let ang = (v.atan2() / (std::f64::consts::PI / 4.0)).round() * std::f64::consts::PI / 4.0;
|
||||||
|
last + Vec2::from_angle(ang) * v.hypot()
|
||||||
|
}
|
||||||
|
|
||||||
/// The handles a pen path shows while it is drawn ([`Overlay::pen_handles`]): the last anchor's in
|
/// The handles a pen path shows while it is drawn ([`Overlay::pen_handles`]): the last anchor's in
|
||||||
/// and out handles and the one before's out handle, those that aren't zero.
|
/// and out handles and the one before's out handle, those that aren't zero.
|
||||||
fn pen_handles(points: &[(Point, Vec2, Vec2)]) -> Vec<[f64; 4]> {
|
fn pen_handles(points: &[(Point, Vec2, Vec2)]) -> Vec<[f64; 4]> {
|
||||||
@@ -1085,6 +1092,8 @@ impl Session {
|
|||||||
guides = g;
|
guides = g;
|
||||||
self.tool.overlay.cursor = Cursor::Pen(self.pen_cursor(&doc, &sel, to, ev.zoom));
|
self.tool.overlay.cursor = Cursor::Pen(self.pen_cursor(&doc, &sel, to, ev.zoom));
|
||||||
if let Some((last, _, out)) = self.tool.pen.as_ref().and_then(|pen| pen.points.last()) {
|
if let Some((last, _, out)) = self.tool.pen.as_ref().and_then(|pen| pen.points.last()) {
|
||||||
|
// With Shift the band ends where a click puts the point (#970).
|
||||||
|
let to = if ev.shift { at_45_degrees(*last, to) } else { to };
|
||||||
self.tool.overlay.rubber = Some([last.x, last.y, to.x, to.y]);
|
self.tool.overlay.rubber = Some([last.x, last.y, to.x, to.y]);
|
||||||
self.tool.overlay.rubber_handle = (out.hypot() > 0.0).then_some([last.x + out.x, last.y + out.y]);
|
self.tool.overlay.rubber_handle = (out.hypot() > 0.0).then_some([last.x + out.x, last.y + out.y]);
|
||||||
}
|
}
|
||||||
@@ -2094,9 +2103,7 @@ impl Session {
|
|||||||
if ev.shift
|
if ev.shift
|
||||||
&& let Some((last, _, _)) = pen.points.last()
|
&& let Some((last, _, _)) = pen.points.last()
|
||||||
{
|
{
|
||||||
let v = p - *last;
|
p = at_45_degrees(*last, p);
|
||||||
let ang = (v.atan2() / (std::f64::consts::PI / 4.0)).round() * std::f64::consts::PI / 4.0;
|
|
||||||
p = *last + Vec2::from_angle(ang) * v.hypot();
|
|
||||||
}
|
}
|
||||||
pen.points.push((p, Vec2::ZERO, Vec2::ZERO));
|
pen.points.push((p, Vec2::ZERO, Vec2::ZERO));
|
||||||
self.tool.gesture = Gesture::PenDrag { anchor: p };
|
self.tool.gesture = Gesture::PenDrag { anchor: p };
|
||||||
|
|||||||
Reference in New Issue
Block a user