mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
Join the selected end points of two paths with Ctrl+J
Fixes #4163 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Haiku 5.5
parent
6259448c39
commit
b089b7e948
@@ -467,6 +467,9 @@ fn join(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if a == b {
|
||||
return Err(bad(C, "join two different paths"));
|
||||
}
|
||||
let st = s.doc()?;
|
||||
let picked_a = st.selection.anchors.get(&a).cloned().unwrap_or_default();
|
||||
let picked_b = st.selection.anchors.get(&b).cloned().unwrap_or_default();
|
||||
s.edit("Join", |d, sel| {
|
||||
let pb = d.node(b).and_then(|n| n.path_data()).cloned().ok_or(EngineError::NoNode(b))?;
|
||||
let pa = path_mut(d, a)?;
|
||||
@@ -481,8 +484,24 @@ fn join(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
// The ends asked for, else the closest pair.
|
||||
let cands =
|
||||
[(xl.distance(yf), false, false), (xl.distance(yl), false, true), (xf.distance(yf), true, false), (xf.distance(yl), true, true)];
|
||||
let (rx, ry) =
|
||||
ends.unwrap_or_else(|| cands.into_iter().min_by(|p, q| p.0.total_cmp(&q.0)).map_or((false, false), |(_, rx, ry)| (rx, ry)));
|
||||
// Direct-selected end points decide which ends meet, before the closest pair does.
|
||||
let end_of = |picked: &std::collections::BTreeSet<(usize, usize)>, si: usize, len: usize| {
|
||||
let last_ix = len.checked_sub(1)?;
|
||||
let first = picked.contains(&(si, 0));
|
||||
let last = picked.contains(&(si, last_ix));
|
||||
match (first, last) {
|
||||
(true, false) => Some(true),
|
||||
(false, true) => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let by_selection = match (end_of(&picked_a, sa, x.anchors.len()), end_of(&picked_b, sb, y.anchors.len())) {
|
||||
(Some(fa), Some(fb)) => Some((fa, !fb)),
|
||||
_ => None,
|
||||
};
|
||||
let (rx, ry) = ends
|
||||
.or(by_selection)
|
||||
.unwrap_or_else(|| cands.into_iter().min_by(|p, q| p.0.total_cmp(&q.0)).map_or((false, false), |(_, rx, ry)| (rx, ry)));
|
||||
if rx {
|
||||
x.reverse();
|
||||
}
|
||||
|
||||
@@ -2188,6 +2188,20 @@ fn join_takes_the_paths_and_the_ends_to_join() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Without `ends`, the end points picked with the direct selection are the ones joined.
|
||||
#[test]
|
||||
fn join_uses_the_selected_end_points() {
|
||||
let mut s = session();
|
||||
let a = line(&mut s, 0.0, 0.0, 100.0, 0.0);
|
||||
let b = line(&mut s, 110.0, 0.0, 200.0, 0.0);
|
||||
s.execute("select.all", &json!({})).unwrap();
|
||||
s.execute("select.anchors", &json!({"id": a.0, "anchors": [[0, 0]], "mode": "add"})).unwrap();
|
||||
s.execute("select.anchors", &json!({"id": b.0, "anchors": [[0, 1]], "mode": "add"})).unwrap();
|
||||
s.execute("path.join", &json!({})).unwrap();
|
||||
let pts: Vec<(f64, f64)> = path(&s, a).subpaths[0].anchors.iter().map(|x| (x.p.x, x.p.y)).collect();
|
||||
assert_eq!(pts, [(100.0, 0.0), (0.0, 0.0), (200.0, 0.0), (110.0, 0.0)]);
|
||||
}
|
||||
|
||||
/// `path.join {to}` makes the joined anchor a corner or smooth point.
|
||||
#[test]
|
||||
fn join_to_corner_or_smooth_sets_the_merged_anchor() {
|
||||
|
||||
Reference in New Issue
Block a user