From 345f7b3d5b64cef6e75f907c4d47f5b5658f1eba Mon Sep 17 00:00:00 2001 From: Codex-ytr83r Date: Sat, 12 Sep 2026 18:46:13 -0700 Subject: [PATCH] Keep reconstructed label corridors finite and inside blockers --- .../src/behavior/scenario_label/corridor.rs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/crates/oa-desktop/src/behavior/scenario_label/corridor.rs b/crates/oa-desktop/src/behavior/scenario_label/corridor.rs index 5ad0aac2..efc63888 100644 --- a/crates/oa-desktop/src/behavior/scenario_label/corridor.rs +++ b/crates/oa-desktop/src/behavior/scenario_label/corridor.rs @@ -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)); + } }