Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-demo/tests/osm3d_spoke.rs

//! Regression (test-matrix), REAL DATA: the OSM 3D viewer fed real liechtenstein
//! GeoParquet must never project a "spoke" face — the starburst the user saw.
//! Builds `Map3D::from_geometry` exactly like the demo tab, sweeps the auto-orbit,
//! and asserts via `shade_faces` DATA that no projected face spans far past the
//! viewport (a near-plane projection artifact). Emits to the matrix.
//!
//! Sensitivity: with the `shade_faces` near-spoke reject removed, the orbit hits
//! an angle where the terrain quad straddles the near plane and `worst` jumps to
//! ~1e5 px → this test fails. With the fix it stays a few hundred px.

use egui::{Color32, Pos2};
use facett_demo::osm_tabs;
use facett_map3d::{Map3D, ViewPreset};

#[test]
fn osm3d_real_data_never_projects_spoke_faces() {
    let geo = osm_tabs::load();
    let mut m = Map3D::from_geometry("osm3d-spoke", &geo.ways_3d);
    let half_h = 450.0f32;
    // VIEWPORT-TIGHT cap over the REAL OSM fixture (was `half_h * 8.0`, the same
    // loophole as facett-map3d/tests/no_spokes.rs but on real data).
    // `SCREEN_BOUND_K = 1.0` ⇒ a fully-clipped face spans at most 2·half_h.
    let cap = half_h * 2.0 + 1.0;
    let center = Pos2::new(450.0, 450.0);

    let mut worst = 0f32;
    let mut faces_total = 0usize;

    // (a) fixed presets incl. Front (horizon-level) — the LOW angle the auto-orbit
    //     never reaches, where the terrain quad's far edge straddles the near plane.
    for p in [ViewPreset::Front, ViewPreset::Oblique, ViewPreset::Isometric, ViewPreset::Top] {
        let mut mp = Map3D::from_geometry("osm3d-preset", &geo.ways_3d);
        mp.view_preset(p);
        let faces = mp.shade_faces(center, half_h, Color32::GRAY);
        faces_total += faces.len();
        let mut pw = 0f32;
        for (_, t, _) in &faces {
            let ex = t[0].x.max(t[1].x).max(t[2].x) - t[0].x.min(t[1].x).min(t[2].x);
            let ey = t[0].y.max(t[1].y).max(t[2].y) - t[0].y.min(t[1].y).min(t[2].y);
            pw = pw.max(ex.max(ey));
        }
        eprintln!("EMIT_REAL3D preset {p:?}: worst={pw:.0}px faces={}", faces.len());
        worst = worst.max(pw);
    }

    // (b) auto-orbit sweep.
    for _ in 0..24 {
        m.tick(0.15);
        let faces = m.shade_faces(center, half_h, Color32::GRAY);
        faces_total += faces.len();
        for (_, t, _) in &faces {
            let ex = t[0].x.max(t[1].x).max(t[2].x) - t[0].x.min(t[1].x).min(t[2].x);
            let ey = t[0].y.max(t[1].y).max(t[2].y) - t[0].y.min(t[1].y).min(t[2].y);
            worst = worst.max(ex.max(ey));
        }
    }

    eprintln!("EMIT_REAL3D worst_extent_px={worst:.0} cap_px={cap:.0} faces={faces_total} ways={}", geo.ways_3d.len());
    // Read only by the testmatrix row below.
    #[cfg(feature = "testmatrix")]
    let ok = worst < cap && faces_total > 0;
    assert!(faces_total > 0, "real liechtenstein rendered some faces");
    assert!(worst < cap, "real-data projection spoke: a face spans {worst:.0}px (> cap {cap:.0})");

    #[cfg(feature = "testmatrix")]
    facett::core::testmatrix::emit(
        "facett-map3d",
        "osm3d_real_no_projection_spokes",
        ok,
        &format!("worst_extent_px={worst:.0} cap_px={cap:.0} faces={faces_total}"),
    );
}