Blend: pinning a closed replaced spine gives its end keys points of their own (#6809)

Pinning a closed spine from Replace Spine (a spine edit, Reverse Spine)
stored it closed with both end keys on its first point, so moving the
first key afterwards landed it on the last. Pinning now opens the spine
there as the layout of a moved key does.
This commit is contained in:
HassanKhan
2026-11-12 13:57:30 +05:00
parent a8b5a5b6c9
commit fb9a3a813b
2 changed files with 33 additions and 2 deletions
+6 -2
View File
@@ -1116,8 +1116,12 @@ pub fn pin_spine(keys: &[Arc<Node>], spec: &BlendSpec) -> Option<(PathData, Vec<
&& pinned(spec, keys.len(), first.anchors.len()).is_none()
{
let mut path = PathData::single(first.clone());
let out = spread_anchors(&mut path, keys.len())?;
return Some((path, out));
let mut out = spread_anchors(&mut path, keys.len())?;
// A closed spine's end keys get points of their own, so that once pinned each still
// moves only its own end.
let mut sp = path.subpaths.into_iter().next()?;
open_at_start(&mut sp, &mut out);
return Some((PathData::single(sp), out));
}
let (path, anchors) = blend_spine(keys, spec)?;
Some((path, anchors?))
+27
View File
@@ -484,6 +484,33 @@ fn moving_the_first_key_of_a_closed_replaced_spine_blend_moves_what_is_drawn() {
assert!(center(&back[1]).distance(center(&before[1])) < 1e-6);
}
/// #6809 on a closed spine pinned by a spine edit: the end keys get points of their own, so
/// moving the first key afterwards still moves only its end.
#[test]
fn moving_the_first_key_of_a_pinned_closed_spine_blend_moves_what_is_drawn() {
let mut s = session();
let (a, _, g) = blend(&mut s, json!({"steps": 5}));
let square = id_of(&s.execute("path.create", &json!({"d": "M100 100 L300 100 L300 300 L100 300 Z"})).unwrap());
sel(&mut s, &[g, square]);
s.execute("object.blend.replaceSpine", &json!({})).unwrap();
// Dragging a corner away from the keys pins the spine to them.
s.execute("object.blend.spine.moveAnchor", &json!({"id": g.0, "anchor": 2, "x": 320, "y": 320})).unwrap();
let NodeKind::Blend { spec, .. } = node(&s, g).kind else { panic!() };
assert_eq!(spec.key_anchors.len(), 2, "{:?}", spec.key_anchors);
let center = |n: &Node| n.geometric_bounds().unwrap().center();
let before = steps_of(&s, g);
sel(&mut s, &[a]);
s.execute("object.move", &json!({"dx": -50, "dy": -40})).unwrap();
let key = center(&node(&s, a));
assert!(key.distance(Point::new(50.0, 60.0)) < 1e-6, "{key:?}");
let after = steps_of(&s, g);
assert_eq!(after.len(), before.len());
let drawn = center(&after[0]);
assert!(drawn.distance(key) < 1e-6, "the key is drawn where it was moved to: {drawn:?}, outline at {key:?}");
let last = center(&after[after.len() - 1]);
assert!(last.distance(Point::new(100.0, 100.0)) < 1e-6, "the other key stays put: {last:?}");
}
#[test]
fn blend_align_to_path_rotates_steps() {
let mut s = session();