Keep reconstructed label corridors finite and inside blockers

This commit is contained in:
2026-09-12 18:46:13 -07:00
parent 6a8650669f
commit 345f7b3d5b
@@ -59,7 +59,7 @@ pub(super) fn widest_clear(
}
let candidate = Rectangle {
x: start,
width: end - start,
width: contained_width(start, end),
..band
};
// Use f64 only for comparison distance: subtracting two admitted f32
@@ -83,6 +83,18 @@ pub(super) fn widest_clear(
Ok(best)
}
/// Finite f32 endpoints can subtract to infinity or round across a blocker.
/// Compute in f64, cap to finite f32, and round inward if nearest rounding
/// overshot the admitted interval's end.
fn contained_width(start: f32, end: f32) -> f32 {
let exact = f64::from(end) - f64::from(start);
let mut width = exact.min(f64::from(f32::MAX)) as f32;
if f64::from(start) + f64::from(width) > f64::from(end) {
width = width.next_down();
}
width
}
#[cfg(test)]
mod tests {
use super::*;
@@ -186,4 +198,34 @@ mod tests {
}
assert_eq!(widest_clear(band, &[], f32::INFINITY), Err(InvalidGeometry));
}
#[test]
fn finite_band_cannot_reconstruct_an_infinite_width() {
let band = rect(f32::from_bits(0xfe79636e), 0., f32::MAX, 20.);
let right = band.x + band.width;
assert!(right.is_finite());
assert!(
(right - band.x).is_infinite(),
"counterexample must exercise f32 subtraction overflow"
);
let result = widest_clear(band, &[], 0.).unwrap().unwrap();
assert!(result.width.is_finite() && result.width > 0.);
assert!(result.x + result.width <= right);
assert!(f64::from(result.x) + f64::from(result.width) <= f64::from(right));
}
#[test]
fn reconstructed_width_rounds_inward_at_a_blocker() {
let band = rect(-999_948.562_5, 0., 1_000_000., 20.);
let blocker = rect(2.1, 0., 10., 20.);
assert!(
band.x + (blocker.x - band.x) > blocker.x,
"counterexample must cross the blocker under naive reconstruction"
);
let result = widest_clear(band, &[blocker], 0.).unwrap().unwrap();
assert_eq!(result.x, band.x);
assert!(result.width > 999_000.);
assert!(result.x + result.width <= blocker.x);
assert!(f64::from(result.x) + f64::from(result.width) <= f64::from(blocker.x));
}
}