Reject self-intersecting polygons in polygon_covers_rect

Found while testing crates/geom/src/hit.rs:12-48

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-19 22:19:37 +07:00
committed by bflatastic
co-authored by Claude Haiku 5.5
parent 157679c1a8
commit bdd5470dcf
+22
View File
@@ -28,9 +28,11 @@ pub fn polygon_covers_rect(path: &BezPath, r: Rect, tol: f64) -> bool {
// Convex: every turn goes the same way (straight runs allowed).
let n = pts.len();
let mut sign = 0.0f64;
let mut turning = 0.0f64;
for i in 0..n {
let (a, b, c) = (pts[i], pts[(i + 1) % n], pts[(i + 2) % n]);
let cross = (b - a).cross(c - b);
turning += cross.atan2((b - a).dot(c - b));
if cross.abs() <= 1e-9 {
continue;
}
@@ -40,6 +42,10 @@ pub fn polygon_covers_rect(path: &BezPath, r: Rect, tol: f64) -> bool {
return false;
}
}
// A simple convex polygon turns through exactly one full revolution; a star winds more.
if (turning.abs() - std::f64::consts::TAU).abs() > 1e-6 {
return false;
}
let inner = r.inflate(-tol, -tol);
sign != 0.0
&& [Point::new(inner.x0, inner.y0), Point::new(inner.x1, inner.y0), Point::new(inner.x1, inner.y1), Point::new(inner.x0, inner.y1)]
@@ -244,4 +250,20 @@ mod regress_tests {
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}");
}
#[test]
fn polygon_covers_rect_rejects_self_intersecting_star() {
let mut b = BezPath::new();
for k in 0..5 {
let a = (-90.0 + 144.0 * k as f64).to_radians();
let p = Point::new(100.0 * a.cos(), 100.0 * a.sin());
if k == 0 {
b.move_to(p);
} else {
b.line_to(p);
}
}
b.close_path();
assert!(!polygon_covers_rect(&b, Rect::new(-55.0, -20.0, 55.0, 78.0), 0.01));
}
}