facett-demo/tests/osm3d_shot.rs
//! Render the REAL OSM 3D tab (liechtenstein GeoParquet, not the synthetic
//! rabbit) through egui_kittest's wgpu backend and save a PNG so the agent can
//! SEE what the user sees — the starburst regression that the synthetic-only
//! render_proof never exercised. This is the "test the UI myself" path.
use egui_kittest::Harness;
#[cfg(feature = "map3d-wgpu")]
use egui_kittest::wgpu::{WgpuTestRenderer, create_render_state, default_wgpu_setup};
use facett::Facet;
use facett_demo::osm_tabs::{self, OsmSource};
#[test]
fn osm3d_real_render_to_png() {
let geo = osm_tabs::load();
eprintln!(
"osm3d_shot: source={:?} ways_3d={} ways_2d={} points={}",
geo.source, geo.ways_3d.len(), geo.ways_2d.len(), geo.points.len()
);
assert!(geo.source != OsmSource::Synthetic || !geo.ways_3d.is_empty(),
"want real liechtenstein (or at least some ways)");
// ── Height distribution EMIT + the "no insanely tall buildings" REGRESSION ──
// Buildings must extrude to LOW, VARIED, span-scaled metric heights — not the
// old uniform 0.22 design-unit spike. Compute the real distribution from the
// SAME path the mesh uses and assert it on the actual liechtenstein ways.
let stats = facett::map3d::building_height_stats(&geo.ways_3d, 0.22);
eprintln!("osm3d_shot: [height-dist] {}", stats.to_json());
if stats.buildings > 0 {
let p95_frac = stats.p95 / stats.box_span;
let max_frac = stats.max / stats.box_span;
eprintln!(
"osm3d_shot: buildings={} tagged={} default={} min={:.5} median={:.5} p95={:.5} ({:.2}% box) max={:.5} ({:.2}% box)",
stats.buildings, stats.tagged, stats.defaulted, stats.min, stats.median,
stats.p95, p95_frac * 100.0, stats.max, max_frac * 100.0
);
// p95 must be a low skyline — the old uniform 0.22 lift (≈11% of the box)
// FAILS this. (The fix puts p95 well under 1% of the box for a town.)
assert!(
p95_frac < 0.1,
"buildings must be a low skyline: p95={} ({:.2}% of box) — the old uniform 0.22 spike fails this",
stats.p95, p95_frac * 100.0
);
// The skyline is varied (not one flat roofline).
assert!(stats.max - stats.min > 1e-4, "the real skyline varies (min {} != max {})", stats.min, stats.max);
}
let mut view = osm_tabs::osm3d_view(&geo);
let s = view.state_json();
eprintln!("osm3d_shot: state triangles={} tiles={}", s["triangles"], s["tiles"]);
// Install the Map3D GPU **depth** renderer so the same depth-tested path the
// demo runs draws here — otherwise `osm3d_view`'s `with_gpu(true)` adds a
// no-op callback (no renderer) and the CPU painter is skipped → a black PNG.
let mut builder = Harness::builder().with_size(egui::vec2(1000.0, 1000.0));
#[cfg(feature = "map3d-wgpu")]
{
let rs = create_render_state(default_wgpu_setup(), Default::default());
facett::map3d::gpu::install_renderer(&rs);
builder = builder.renderer(WgpuTestRenderer::from_render_state(rs));
}
let mut harness = builder.build_ui(move |ui| {
facett::core::set_theme(ui.ctx(), facett::core::Theme::sci_fi());
view.ui(ui);
});
harness.run_steps(8);
let img = harness.render().expect("wgpu render produced an image");
image::DynamicImage::ImageRgba8(img)
.save("/tmp/osm3d_liech.png")
.expect("save PNG");
eprintln!("osm3d_shot: saved /tmp/osm3d_liech.png");
// also a 2D shot for comparison
let mut v2 = osm_tabs::osm2d_view(&geo);
let mut h2 = Harness::builder()
.with_size(egui::vec2(1000.0, 1000.0))
.build_ui(move |ui| {
facett::core::set_theme(ui.ctx(), facett::core::Theme::sci_fi());
v2.ui(ui);
});
h2.run_steps(8);
let img2 = h2.render().expect("2d render");
image::DynamicImage::ImageRgba8(img2)
.save("/tmp/osm2d_liech.png")
.expect("save 2D PNG");
eprintln!("osm3d_shot: saved /tmp/osm2d_liech.png");
}