diff --git a/crates/engine/src/cmd/modify2/curve_edits.rs b/crates/engine/src/cmd/modify2/curve_edits.rs index 31ef757..b27f9a5 100644 --- a/crates/engine/src/cmd/modify2/curve_edits.rs +++ b/crates/engine/src/cmd/modify2/curve_edits.rs @@ -228,6 +228,9 @@ fn ends(sp: &Spline) -> (Vec2, Vec2) { /// larger arc or the full ellipse (gaps between them close). Otherwise the objects joined end /// to end with the first one become one spline. The first joined object keeps its handle. pub(crate) fn join_curves(s: &mut Session, hs: &[Handle]) -> Result> { + // A handle named twice is one object: a repeat would join it with itself or remove the result. + let mut seen = std::collections::HashSet::new(); + let hs: Vec = hs.iter().copied().filter(|h| seen.insert(*h)).collect(); let d = s.doc()?; let ents: Vec = hs.iter().filter_map(|h| d.entity(*h).map(|e| (**e).clone())).collect(); if !ents.iter().any(|e| matches!(e.kind, EntityKind::Ellipse(_) | EntityKind::Spline(_))) { diff --git a/crates/engine/tests/modify_curves.rs b/crates/engine/tests/modify_curves.rs index b8a869b..cea710d 100644 --- a/crates/engine/tests/modify_curves.rs +++ b/crates/engine/tests/modify_curves.rs @@ -262,6 +262,26 @@ fn join_merges_elliptical_arcs_on_one_ellipse() { assert_eq!(count(&s), 1); } +#[test] +fn join_names_an_elliptical_arc_twice_without_losing_it() { + // The same arc twice is one object: nothing to join, and the arc stays. + let mut s = Session::new(); + let a = arc_on_ellipse(&mut s, 0.0, 90.0); + let before = ellipse(&s, &a); + assert!(s.execute("join", &json!({ "handles": [a, a] })).is_err()); + assert_eq!(count(&s), 1); + assert_eq!(ellipse(&s, &a), before); + // Repeating the source next to a second arc still merges the two into the source. + let mut s = Session::new(); + let a = arc_on_ellipse(&mut s, 0.0, 90.0); + let b = arc_on_ellipse(&mut s, 90.0, 180.0); + let r = s.execute("join", &json!({ "handles": [a, a, b] })).unwrap(); + assert_eq!(h(&r), a); + let m = ellipse(&s, &a); + assert!(m.start.abs() < 1e-9 && (m.end - PI).abs() < 1e-9, "{m:?}"); + assert_eq!(count(&s), 1); +} + #[test] fn join_makes_one_spline_from_lines_arcs_polylines_and_splines() { let mut s = Session::new();