M0.2: hit-test distance exact on cusp-like cubics (nearest-point accuracy 1e-9; proptest regression)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-02 00:16:23 -04:00
parent c878ac994c
commit 1e7b4308ec
1 changed files with 24 additions and 1 deletions

View File

@ -15,7 +15,7 @@ pub fn fill_contains(path: &BezPath, rule: FillRule, p: Point) -> bool {
/// Distance from `p` to the nearest point on the path outline.
pub fn distance_to_outline(path: &BezPath, p: Point) -> f64 {
path.segments().map(|s| s.nearest(p, 1e-6).distance_sq).fold(f64::INFINITY, f64::min).sqrt()
path.segments().map(|s| s.nearest(p, 1e-9).distance_sq).fold(f64::INFINITY, f64::min).sqrt()
}
/// Is `p` within `tol` of the path's stroke of width `width`?
@ -91,3 +91,26 @@ mod tests {
assert!(intersects_rect(&l, Rect::new(4.0, 0.0, 6.0, 10.0)));
}
}
#[cfg(test)]
mod regress_tests {
use super::*;
use kurbo::{CubicBez, ParamCurve};
/// A cubic whose handles sit on its anchors on one side (cusp-like): points on the curve are
/// at distance ~0 (proptest regression).
#[test]
fn nearest_on_degenerate_cubic() {
let c = CubicBez::new(
(131.69052599341336, 172.64518298885875),
(104.00879084385166, 172.64518298885875),
(145.71215277397286, 141.82358989609716),
(131.4188160942415, 162.38678549385997),
);
let mut bp = BezPath::new();
bp.move_to(c.p0);
bp.curve_to(c.p1, c.p2, c.p3);
let worst = (0..=200).map(|i| distance_to_outline(&bp, c.eval(i as f64 / 200.0))).fold(0.0, f64::max);
assert!(worst < 1e-6, "{worst}");
}
}