From 13a4d271d4f34381125c317eeaec499f46911eb8 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 12 Nov 2026 17:24:18 -0800 Subject: [PATCH] Mesh: locating a point searches only the edges near it locate_within measured every boundary edge of the mesh at full accuracy for each lookup, including points well inside the mesh. It now skips an edge whose control points all lie farther than the distance it is looking for: a millionth of a point for the outline, or the tolerance for a point outside. --- crates/doc/src/live/mesh.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/doc/src/live/mesh.rs b/crates/doc/src/live/mesh.rs index 91d814a42d..d912479464 100644 --- a/crates/doc/src/live/mesh.rs +++ b/crates/doc/src/live/mesh.rs @@ -1449,15 +1449,14 @@ impl GradientMesh { // A point on the outline takes the nearest point of the edge on every side: the nonzero // winding number counts a point on some edges as outside (a rectangle's bottom and right // edges) and on the others as inside. - let edge = self.nearest_edge(p); - if let Some((_, r, c, u, v)) = edge.filter(|e| e.0 <= ON_OUTLINE * ON_OUTLINE) { + if let Some((_, r, c, u, v)) = self.nearest_edge(p, ON_OUTLINE).filter(|e| e.0 <= ON_OUTLINE * ON_OUTLINE) { return Some((r, c, u, v)); } if self.outline().to_bezpath().winding(p) == 0 { if tol.is_nan() || tol <= 0.0 { return None; } - return edge.filter(|e| e.0 <= tol * tol).map(|(_, r, c, u, v)| (r, c, u, v)); + return self.nearest_edge(p, tol).filter(|e| e.0 <= tol * tol).map(|(_, r, c, u, v)| (r, c, u, v)); } const N: usize = 16; let mut best = (f64::INFINITY, 0, 0, 0.0, 0.0); @@ -1495,12 +1494,20 @@ impl GradientMesh { } /// The point of the mesh's outer edge nearest `p`: its squared distance from `p`, and its - /// boundary patch and local (u, v). - fn nearest_edge(&self, p: Point) -> Option<(f64, usize, usize, f64, f64)> { + /// boundary patch and local (u, v). Edges whose control points all lie farther than `within` + /// from `p` are skipped, so `None` means no edge is within `within`. + fn nearest_edge(&self, p: Point, within: f64) -> Option<(f64, usize, usize, f64, f64)> { use vectorcraft_geom::kurbo::ParamCurveNearest; let (rows, cols) = (self.rows as usize, self.cols as usize); let mut best: Option<(f64, usize, usize, f64, f64)> = None; let mut take = |e: CubicBez, at: (usize, usize, Option, Option)| { + // The edge lies inside its control points' box, so a box farther than `within` holds + // no point of the edge within it. + let b = Rect::from_points(e.p0, e.p1).union_pt(e.p2).union_pt(e.p3); + let (dx, dy) = ((b.x0 - p.x).max(p.x - b.x1).max(0.0), (b.y0 - p.y).max(p.y - b.y1).max(0.0)); + if dx * dx + dy * dy > within * within { + return; + } let n = e.nearest(p, 1e-9); if best.is_none_or(|b| n.distance_sq < b.0) { let (r, c, u, v) = at;