facett-map3d/tests/road_hierarchy_proof.rs
//! **Road-hierarchy A/B proof (headless, data-level).** The `road_ribbon`
//! extruder already styles roads by class — a motorway (`style.rs` width `3.0`)
//! lays a wider casing/fill/glow ribbon than a residential street (`1.0`). This
//! test PROVES that as DATA on the extruded [`Mesh3`] with no GPU and no pixels:
//! same centreline geometry, only the class differs → the higher-class road's
//! ribbon vertices span WIDER, with the SAME vertex count (it's width, not more
//! tessellation), and the build is deterministic.
//!
//! This is the "garmin road hierarchy" feature's coverage cell (was untested).
//! Run: `cargo test -p facett-map3d --test road_hierarchy_proof [--features testmatrix]`.
use facett_map::Way;
use facett_map3d::extrude;
const H: f32 = 1.0;
/// A single road with the given `style` width (the class knob: 1.0 residential ..
/// 3.0 motorway). Fixed L-shaped centreline so the footprint bbox is non-degenerate
/// (both axes span) and the projection is identical for every class.
fn road(width: f32) -> Way {
Way::line(
1,
"road",
vec![(0.0, 0.0), (0.010, 0.0), (0.010, 0.006)],
egui::Color32::from_rgb(200, 200, 200),
width,
)
}
/// The perpendicular "spread" of a road's ribbon vertices = (x-extent + z-extent)
/// of everything the extruder added AFTER the fixed terrain quad. Same centreline
/// → the only thing that grows this between two classes is the ribbon half-width.
fn road_span(width: f32) -> (f32, usize) {
// Terrain-only build (empty ways returns early after the terrain quad) gives
// the vertex offset where the road's ribbon vertices begin.
let n_terrain = extrude::build(&[], H).0.vertex_count();
let (mesh, _) = extrude::build(&[road(width)], H);
let verts = &mesh.positions[n_terrain..];
assert!(!verts.is_empty(), "the road produced ribbon geometry");
let (mut xmin, mut xmax, mut zmin, mut zmax) = (f32::MAX, f32::MIN, f32::MAX, f32::MIN);
for p in verts {
xmin = xmin.min(p[0]);
xmax = xmax.max(p[0]);
zmin = zmin.min(p[2]);
zmax = zmax.max(p[2]);
}
((xmax - xmin) + (zmax - zmin), verts.len())
}
#[test]
fn motorway_ribbon_is_wider_than_residential_same_geometry() {
let (motorway, motor_n) = road_span(3.0); // motorway class
let (primary, _) = road_span(2.2); // primary
let (residential, res_n) = road_span(1.0); // residential
// (1) width-by-class: higher road class → wider ribbon spread, monotonically.
assert!(
motorway > primary && primary > residential,
"road hierarchy: motorway {motorway:.5} > primary {primary:.5} > residential {residential:.5}"
);
// A clear margin (glow half-width scales with the class width, so a motorway's
// spread exceeds a residential's by well over any float noise).
assert!(
motorway - residential > 1e-3,
"motorway ribbon is meaningfully wider (Δ {:.5})",
motorway - residential
);
// (2) it's WIDTH, not more geometry: identical centreline → identical vertex
// count across classes (the class only moves vertices outward, adds none).
assert_eq!(
motor_n, res_n,
"same centreline → same vertex count ({motor_n} vs {res_n}); the class changes width, not tessellation"
);
// (3) determinism (FC-7): a re-extrude is identical.
let (again, _) = road_span(3.0);
assert_eq!(motorway, again, "extrude is deterministic");
#[cfg(feature = "testmatrix")]
{
let ok = motorway > primary && primary > residential && motor_n == res_n && motorway == again;
facett_core::testmatrix::emit(
"facett-map3d",
"road_hierarchy_width_by_class",
ok,
&format!(
"motorway={motorway:.5} primary={primary:.5} residential={residential:.5} verts={motor_n} deterministic={}",
motorway == again
),
);
}
}