#1280: PathData::bounds closes a NaN anchor as kurbo does; the perf row names what it times

Follow-up to CodeRabbit's review of #5778.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FredApps
2026-11-05 17:17:36 +07:00
committed by bflatastic
co-authored by Claude Opus 5.5
parent b13335d188
commit c1f7e4ed6d
2 changed files with 21 additions and 3 deletions
+3 -2
View File
@@ -214,12 +214,13 @@ fn pointing(n: usize, rows: &mut Vec<(String, f64)>) -> Result<(), String> {
format!("smart guide targets in view ({n} paths)"),
median_ms(5, || drop(vectorcraft_engine::tools::guides::Targets::collect(&doc, &[], Some(view_rect)))),
));
// Shift-clicking one more object into a selection of half the document.
// Adding one more object to a selection of half the document: the command a shift-click ends
// in, without the pointer handling and hit test before it.
let ids: Vec<u64> = doc.layers[0].children().map(|c| c.iter().map(|n| n.id.0).collect()).unwrap_or_default();
s.execute("select.set", &json!({"ids": ids[..ids.len() / 2]})).map_err(err)?;
let mut k = ids.len() / 2;
rows.push((
format!("shift-click into a {}-object selection", ids.len() / 2),
format!("select.toggle in a {}-object selection", ids.len() / 2),
median_ms(5, || {
k += 1;
let _ = s.execute("select.toggle", &json!({"id": ids[k % ids.len()]}));
+18 -1
View File
@@ -562,13 +562,21 @@ impl PathData {
}
let mut bbox: Option<Rect> = None;
for sp in &self.subpaths {
// (a closed subpath's last segment ends on its first anchor: its `ClosePath` adds no line)
for i in 0..sp.segment_count() {
let c = sp.segment(i);
// `to_bezpath_into` writes a line where neither handle is out, else a cubic.
let seg = segment_bounds(if sp.segment_is_line(i) { PathSeg::Line(kurbo::Line::new(c.p0, c.p3)) } else { PathSeg::Cubic(c) });
bbox = Some(bbox.map_or(seg, |bb| bb.union(seg)));
}
// A closed subpath's last segment ends on its first anchor, so its `ClosePath` adds no
// line, unless that anchor is NaN: it then differs from itself, and kurbo closes with one.
if sp.closed
&& let Some(a) = sp.anchors.first()
&& (a.p.x.is_nan() || a.p.y.is_nan())
{
let seg = segment_bounds(PathSeg::Line(kurbo::Line::new(a.p, a.p)));
bbox = Some(bbox.map_or(seg, |bb| bb.union(seg)));
}
}
Some(bbox.unwrap_or_default())
}
@@ -764,6 +772,15 @@ mod tests {
let lone = PathData::new(vec![SubPath::polyline(&[Point::new(5.0, 5.0)], false), SubPath::polyline(&[Point::new(9.0, 1.0)], true)]);
assert_eq!(lone.bounds(), Some(Rect::ZERO));
assert_eq!(bits(lone.bounds()), bits(reference(&lone)));
// A NaN anchor differs from itself: kurbo closes such a subpath with a line of its own.
let nan = Point::new(f64::NAN, 1.0);
let closed = |pts: &[Point]| SubPath::polyline(pts, true);
for pd in [
PathData::new(vec![closed(&[nan]), closed(&[Point::new(5.0, 5.0)])]),
PathData::new(vec![closed(&[nan, Point::new(3.0, 4.0), Point::new(6.0, 1.0)])]),
] {
assert_eq!(bits(pd.bounds()), bits(reference(&pd)));
}
}
fn square() -> PathData {