PERF-2 P1: exact chunked polyline index for the O-grid's sliding outer ring — PolylineIndex::nearest returns nearest_on_polyline's point bit for bit (same segments, same order, same strict minimum; chunks skipped only when their box is farther than the best by more than 1e-12 relative), used by the Winslow sweep and the two ring projections; pin: 0 mismatches over 39,864 queries on a 3,166-point rounded outline including vertices, mid-points and ties
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Build CPU-Only (Explicit) (push) Failing after 5s
Documentation / Build API Documentation (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 6s
CI / Format Check (push) Failing after 22s
CI / Build (ubuntu-latest) (push) Failing after 2m34s
CI / Clippy Check (push) Failing after 3m6s
Performance Benchmarks / Run Benchmarks (push) Successful in 3m47s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YJPeT6WA2e7YvAnS875AHL
This commit is contained in:
Omar Sobh
2026-09-15 23:08:09 -05:00
co-authored by Claude Fable 5.1
parent 11f71b832c
commit 01830e5c8d
2 changed files with 176 additions and 10 deletions
@@ -280,7 +280,88 @@ fn point_at_fraction(pts: &[[f64; 2]], cum: &[f64], f: f64) -> [f64; 2] {
}
/// Nearest point on the closed polyline `pts` to `q` (segment projection).
fn nearest_on_polyline(pts: &[[f64; 2]], q: [f64; 2]) -> [f64; 2] {
/// Chunked bounding boxes over a closed polyline for EXACT nearest-point
/// queries (PERF-2 P1, `docs/perf2_campaign.md`): [`Self::nearest`] returns
/// the same point as [`nearest_on_polyline`] — the same segments are tested
/// in the same order with the same strict-minimum rule — but skips every
/// chunk of segments whose box is farther from the query than the best
/// distance so far (with a 1e-12 relative margin, so a box's rounded
/// lower bound can never hide a segment that could still win).
pub struct PolylineIndex<'a> {
pts: &'a [[f64; 2]],
chunk: usize,
/// Per chunk: `[xmin, xmax, ymin, ymax]` of its segments' end points.
boxes: Vec<[f64; 4]>,
}
impl<'a> PolylineIndex<'a> {
/// Index `pts` (a closed polyline: segment `i` joins `pts[i]` and
/// `pts[(i + 1) % n]`) in chunks of 32 segments.
pub fn new(pts: &'a [[f64; 2]]) -> Self {
let n = pts.len();
let chunk = 32;
let boxes = (0..n.div_ceil(chunk))
.map(|c| {
let mut b = [
f64::INFINITY,
f64::NEG_INFINITY,
f64::INFINITY,
f64::NEG_INFINITY,
];
let start = c * chunk;
let end = (start + chunk).min(n);
// The chunk's segments' end points: `start..=end` (wrapping).
for i in start..=end {
let p = pts[i % n];
b[0] = b[0].min(p[0]);
b[1] = b[1].max(p[0]);
b[2] = b[2].min(p[1]);
b[3] = b[3].max(p[1]);
}
b
})
.collect();
Self { pts, chunk, boxes }
}
/// The nearest point of the polyline to `q`, bit for bit the answer of
/// [`nearest_on_polyline`].
pub fn nearest(&self, q: [f64; 2]) -> [f64; 2] {
let pts = self.pts;
let n = pts.len();
let (mut best, mut best_d) = (pts[0], f64::INFINITY);
for (c, b) in self.boxes.iter().enumerate() {
let dx = (b[0] - q[0]).max(0.0).max(q[0] - b[1]);
let dy = (b[2] - q[1]).max(0.0).max(q[1] - b[3]);
if dx * dx + dy * dy > best_d * (1.0 + 1e-12) {
continue;
}
let start = c * self.chunk;
let end = (start + self.chunk).min(n);
for i in start..end {
let (a, b) = (pts[i], pts[(i + 1) % n]);
let (dx, dy) = (b[0] - a[0], b[1] - a[1]);
let l2 = dx * dx + dy * dy;
let t = if l2 > 0.0 {
(((q[0] - a[0]) * dx + (q[1] - a[1]) * dy) / l2).clamp(0.0, 1.0)
} else {
0.0
};
let p = [a[0] + t * dx, a[1] + t * dy];
let d = (p[0] - q[0]).powi(2) + (p[1] - q[1]).powi(2);
if d < best_d {
best_d = d;
best = p;
}
}
}
best
}
}
/// The nearest point of the closed polyline `pts` to `q` by a scan of every
/// segment (the reference for [`PolylineIndex`]).
pub fn nearest_on_polyline(pts: &[[f64; 2]], q: [f64; 2]) -> [f64; 2] {
let n = pts.len();
let (mut best, mut best_d) = (pts[0], f64::INFINITY);
for i in 0..n {
@@ -489,10 +570,11 @@ pub fn winslow_smooth(
sweeps += 1;
moved = 0.0;
if let Some(curve) = outer_curve {
let index = PolylineIndex::new(curve);
for i in 0..ns {
let (a, b) = (x[nn - 2][i], x[nn - 1][i]);
let cand = [2.0 * b[0] - a[0], 2.0 * b[1] - a[1]];
let p = nearest_on_polyline(curve, cand);
let p = index.nearest(cand);
let d = ((p[0] - x[nn][i][0]).powi(2) + (p[1] - x[nn][i][1]).powi(2)).sqrt();
moved = moved.max(d);
x[nn][i] = p;
@@ -1109,6 +1191,7 @@ fn o_grid_from_outline(
let t0 = std::time::Instant::now();
let hull = convex_hull(hull_src);
let outer_poly = offset_convex_polygon(&hull, offset, 24);
let outer_index = PolylineIndex::new(&outer_poly);
regen_charge(1, t0);
let t0 = std::time::Instant::now();
// Initial outer ring: the inner point pushed along its outward normal
@@ -1125,10 +1208,7 @@ fn o_grid_from_outline(
let (dx, dy) = (next[0] - prev[0], next[1] - prev[1]);
let l = (dx * dx + dy * dy).sqrt().max(1e-300);
let normal = [-dy / l, dx / l];
nearest_on_polyline(
&outer_poly,
[cur[0] + offset * normal[0], cur[1] + offset * normal[1]],
)
outer_index.nearest([cur[0] + offset * normal[0], cur[1] + offset * normal[1]])
})
.collect();
regen_charge(2, t0);
@@ -1146,10 +1226,7 @@ fn o_grid_from_outline(
// rows' converged distribution (the crude normal push would
// undo it every build — measured as the interior moving
// 0.05 h with the wall at rest).
rows[nn] = rows[nn]
.iter()
.map(|&p| nearest_on_polyline(&outer_poly, p))
.collect();
rows[nn] = rows[nn].iter().map(|&p| outer_index.nearest(p)).collect();
rows
}
None => eta