facett-map3d/tests/near_plane_probe.rs
//! **The street-level near-plane oracle.** Was a *temporary diagnostic probe*
//! with **NO assertions at all** — only `eprintln!` — which the fat-list
//! inventory correctly flagged as vacuous (it violated the inject-and-assert
//! law: a test that cannot fail is not a test). It now asserts the contract it
//! was only ever printing, at the worst-case pose it was built to find:
//!
//! * the pose renders REAL geometry (a silently-empty street-level frame is the
//! other failure mode a print-only probe hides);
//! * every projected face is bounded by the VIEWPORT (2·half_h) — the same
//! viewport-tight cap the rest of the map3d smear suite now uses, never a
//! loose multiple of it;
//! * after the live Sutherland-Hodgman rect clip **zero** vertices escape the
//! widget rect — the real on-screen leak this pose was hunting.
//!
//! The pre-fix pipeline (`shade_faces_clip(.., near_clip = false)`) is driven
//! through the SAME probe as the fail-on-bug control, so each assertion is proven
//! to be RED when the defect is reintroduced.
use egui::{Color32, Pos2};
use facett_core::Theme;
use facett_map::Way;
use facett_map3d::{Map3D, V3, ViewPreset};
fn building(id: i64, ring: &[(f64, f64)]) -> Way {
let tags = vec![("building".to_string(), "yes".to_string())];
Way::from_lonlat(id, ring, &tags, &Theme::default()).expect("a building way")
}
fn town() -> Vec<Way> {
let mut ways = Vec::new();
let mut id = 1;
for r in 0..6 {
for c in 0..6 {
let bx = 9.50 + c as f64 * 0.0015;
let by = 47.10 + r as f64 * 0.0015;
ways.push(building(
id,
&[(bx, by), (bx + 0.0008, by), (bx + 0.0008, by + 0.0008), (bx, by + 0.0008), (bx, by)],
));
id += 1;
}
}
ways
}
#[test]
fn probe_street_level_faces() {
let mut m = Map3D::from_ways("probe", &town(), 0.22);
m.spin = false;
// Dolly all the way in, low angle, at the centre of the town — buildings
// straddle the near plane.
m.cam.target = V3::new(0.0, 0.02, 0.0);
m.cam.goal_target = m.cam.target;
m.cam.distance = 0.42;
m.cam.goal_distance = 0.42;
m.view_preset(ViewPreset::Front);
m.cam.elevation = 0.03;
m.cam.goal_elevation = 0.03;
m.cam.settle();
let rect = egui::Rect::from_min_max(Pos2::new(100.0, 80.0), Pos2::new(820.0, 700.0));
let center = rect.center();
let scale = rect.height() * 0.5;
let faces = m.shade_faces(center, scale, Color32::from_rgb(20, 24, 40));
eprintln!("faces emitted: {}", faces.len());
let mut escaped = 0;
let mut worst = 0.0f32;
for (_d, pts, _c) in &faces {
for p in pts {
let dx = (p.x - center.x).abs() - rect.width() * 0.5;
let dy = (p.y - center.y).abs() - rect.height() * 0.5;
let over = dx.max(dy);
if over > 0.0 {
escaped += 1;
worst = worst.max(over);
}
}
}
eprintln!("raw vertices escaping rect: {escaped}, worst overshoot {worst:.1}px");
// Now emulate the EXACT live clip (Sutherland-Hodgman to the rect) and check
// whether any clipped vertex still escapes — that's the real on-screen leak.
let clip = |tri: &[Pos2; 3]| -> Vec<Pos2> {
let mut poly: Vec<Pos2> = tri.to_vec();
let edges: [(f32, u8); 4] = [(rect.left(), 0), (rect.right(), 1), (rect.top(), 2), (rect.bottom(), 3)];
for (bound, which) in edges {
if poly.is_empty() {
break;
}
let inside = |p: &Pos2| match which {
0 => p.x >= bound,
1 => p.x <= bound,
2 => p.y >= bound,
_ => p.y <= bound,
};
let intersect = |a: &Pos2, b: &Pos2| -> Pos2 {
let t = match which {
0 | 1 => (bound - a.x) / (b.x - a.x),
_ => (bound - a.y) / (b.y - a.y),
};
let t = t.clamp(0.0, 1.0);
Pos2::new(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t)
};
let mut out: Vec<Pos2> = Vec::new();
for i in 0..poly.len() {
let cur = poly[i];
let prev = poly[(i + poly.len() - 1) % poly.len()];
let (cin, pin) = (inside(&cur), inside(&prev));
if cin {
if !pin {
out.push(intersect(&prev, &cur));
}
out.push(cur);
} else if pin {
out.push(intersect(&prev, &cur));
}
}
poly = out;
}
poly
};
let eps = 1e-2;
let mut clipped_escapes = 0;
let mut worst_clipped = 0.0f32;
for (_d, pts, _c) in &faces {
for p in &clip(pts) {
let over = ((p.x - center.x).abs() - rect.width() * 0.5).max((p.y - center.y).abs() - rect.height() * 0.5);
if over > eps {
clipped_escapes += 1;
worst_clipped = worst_clipped.max(over);
}
}
}
eprintln!("AFTER clip: escapes {clipped_escapes}, worst {worst_clipped:.1}px");
// ── THE ASSERTIONS (this file used to have none) ─────────────────────────
assert!(!faces.is_empty(), "the street-level pose must render real geometry, not an empty frame");
// (1) VIEWPORT-TIGHT extent bound. `SCREEN_BOUND_K = 1.0` ⇒ the screen-bound
// clip box is ±scale, so a fully-clipped face spans at most 2·scale; +1px
// float-boundary epsilon. Never a loose multiple of the viewport.
let cap = scale * 2.0 + 1.0;
let worst_extent = max_extent(&faces);
assert!(
worst_extent <= cap,
"a face spans {worst_extent:.0}px at street level (viewport cap {cap:.0}px) — the smear regressed"
);
// (2) ZERO on-screen leak after the live rect clip. This is the exact
// quantity the probe printed and never checked.
assert_eq!(
clipped_escapes, 0,
"after the rect clip {clipped_escapes} vertices still escape (worst {worst_clipped:.1}px) — \
the painter would ink outside its allocated rect"
);
// (3) FAIL-ON-BUG control: the pre-fix pipeline at this same pose BREACHES the
// viewport cap, so assertion (1) is proven RED when the defect returns.
let broken = m.shade_faces_clip(center, scale, Color32::from_rgb(20, 24, 40), false);
let broken_extent = max_extent(&broken);
eprintln!("[near_plane_probe] fixed_extent={worst_extent:.0}px broken_extent={broken_extent:.0}px cap={cap:.0}px");
assert!(
broken_extent > cap,
"sensitivity control: the pre-fix pipeline must breach the viewport cap at the street-level \
pose (broken={broken_extent:.0}px, cap={cap:.0}px) — otherwise assertion (1) cannot fail"
);
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"facett-map3d",
"street_level_near_plane_bounded_and_leak_free",
worst_extent <= cap && clipped_escapes == 0 && broken_extent > cap,
&format!(
"faces={} fixed_extent_px={worst_extent:.0} cap_px={cap:.0} clipped_escapes={clipped_escapes} broken_extent_px={broken_extent:.0}",
faces.len()
),
);
}
/// The largest projected extent (px) over a face list.
fn max_extent(faces: &[(f32, [Pos2; 3], Color32)]) -> f32 {
faces
.iter()
.map(|(_, tri, _)| {
let ex = tri[0].x.max(tri[1].x).max(tri[2].x) - tri[0].x.min(tri[1].x).min(tri[2].x);
let ey = tri[0].y.max(tri[1].y).max(tri[2].y) - tri[0].y.min(tri[1].y).min(tri[2].y);
ex.max(ey)
})
.fold(0.0, f32::max)
}