From ec907e75c61f311372c3a722bf94c0a25c2fcaa9 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Fri, 13 Nov 2026 11:00:06 -0800 Subject: [PATCH] Path Precision Tools: a place at the end of a closed path's last segment is on the stretch at its first anchor `span_at` read the end of a closed subpath's closing segment as past every stretch, so a click that landed there could leave the path unchanged. It now reads that place as the first anchor. --- crates/pathops/src/addons/pathtools/tests.rs | 4 ++++ crates/pathops/src/addons/pathtools/trim.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/crates/pathops/src/addons/pathtools/tests.rs b/crates/pathops/src/addons/pathtools/tests.rs index 936dfc323e..301da1a57c 100644 --- a/crates/pathops/src/addons/pathtools/tests.rs +++ b/crates/pathops/src/addons/pathtools/tests.rs @@ -585,6 +585,10 @@ fn spans_divide_a_subpath_at_its_places() { assert_eq!(span_at(&open, &three, 0, f64::NAN), None); let two = spans(&ring, &[(3, 0.5), (0, 0.5)]); assert_eq!((span_at(&ring, &two, 0, 0.25), span_at(&ring, &two, 3, 0.75), span_at(&ring, &two, 2, 0.0)), (Some(1), Some(1), Some(0))); + // The closing segment's end is the first anchor: on the stretch that starts there, or runs through it. + let at_first = spans(&ring, &[(0, 0.0), (2, 0.0)]); + assert_eq!((span_at(&ring, &at_first, 3, 1.0), span_at(&ring, &at_first, 0, 0.0)), (Some(0), Some(0))); + assert_eq!((span_at(&ring, &two, 3, 1.0), span_at(&ring, &spans(&ring, &[]), 3, 1.0)), (Some(1), Some(0))); } #[test] diff --git a/crates/pathops/src/addons/pathtools/trim.rs b/crates/pathops/src/addons/pathtools/trim.rs index 18a2a5640b..618f8eb002 100644 --- a/crates/pathops/src/addons/pathtools/trim.rs +++ b/crates/pathops/src/addons/pathtools/trim.rs @@ -83,6 +83,8 @@ pub fn span_at(sp: &SubPath, stretches: &[Span], seg: usize, t: f64) -> Option= nf { u - nf } else { u }; let on = |&(from, to): &Span| (from <= u && u < to) || (sp.closed && from <= u + nf && u + nf < to); stretches.iter().position(on).or_else(|| (!sp.closed && u >= nf).then(|| stretches.len().checked_sub(1)).flatten()) }