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

nordisk/facett

facett-map3d/tests/smear_pose.rs

//! Render the EXACT camera pose the 360°×100-zoom sweep flagged as the worst
//! projected-edge blow-up (the green-spoke smear) and scan the actual pixels with
//! `facett_core::imgscan`. CPU painter path — the path the wasm demo runs.
//!
//! Run: `cargo test -p facett-map3d --test smear_pose -- --nocapture`

use egui::Color32;
use egui_kittest::Harness;
use facett_core::{imgscan, Facet, Theme};
use facett_map::Way;
use facett_map3d::Map3D;

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 giant_city() -> Map3D {
    let mut ways = Vec::new();
    let mut id = 1;
    for r in 0..20 {
        for c in 0..20 {
            let bx = 17.70 + c as f64 * 0.0010;
            let by = 59.61 + r as f64 * 0.0010;
            ways.push(building(
                id,
                &[(bx, by), (bx + 0.0006, by), (bx + 0.0006, by + 0.0006), (bx, by + 0.0006), (bx, by)],
            ));
            id += 1;
        }
    }
    Map3D::from_geometry("giant", &ways)
}

fn render_at(az_deg: f32, elev_deg: f32, dist: f32, name: &str) -> imgscan::ScanReport {
    use std::cell::RefCell;
    use std::rc::Rc;
    let view = Rc::new(RefCell::new(giant_city()));
    {
        let mut m = view.borrow_mut();
        m.spin = false;
        let tgt = m.render_camera().target;
        m.cam.target = tgt;
        m.cam.goal_target = tgt;
        m.cam.azimuth = az_deg.to_radians();
        m.cam.goal_azimuth = az_deg.to_radians();
        m.cam.elevation = elev_deg.to_radians();
        m.cam.goal_elevation = elev_deg.to_radians();
        m.cam.distance = dist;
        m.cam.goal_distance = dist;
        m.cam.settle();
    }
    let v2 = view.clone();
    let mut harness = Harness::builder().with_size(egui::vec2(600.0, 600.0)).build_ui(move |ui| {
        Facet::ui(&mut *v2.borrow_mut(), ui);
    });
    harness.run_steps(3);
    let img = harness.render().expect("render");
    let dir = std::env::temp_dir().join("facett-map3d");
    std::fs::create_dir_all(&dir).ok();
    let png = dir.join(format!("smear_{name}.png"));
    img.save(&png).ok();
    eprintln!("[smear_pose] {name}: wrote {}", png.display());
    let bg = imgscan::Rgba { r: 20, g: 24, b: 40, a: 255 };
    imgscan::scan(img.as_raw(), img.width(), img.height(), bg)
}

#[test]
fn worst_sweep_pose_is_not_a_spoke_smear() {
    // The two worst state vectors the sweep reported.
    let city = render_at(143.0, 5.0, 0.612, "city_az143_e5_d0p61");
    let rabbit_pose = render_at(148.0, 55.0, 0.130, "city_az148_e55_d0p13");

    eprintln!(
        "[smear_pose] city : spoke={:.3} hf={:.3} coverage={:.3}",
        city.spoke_score, city.high_freq_ratio, city.coverage
    );
    eprintln!(
        "[smear_pose] close: spoke={:.3} hf={:.3} coverage={:.3}",
        rabbit_pose.spoke_score, rabbit_pose.high_freq_ratio, rabbit_pose.coverage
    );

    // NOTE: the RIGOROUS smear oracle is `chain_sweep` (worst projected edge ≤
    // viewport across the 360°×100-zoom×elev joint space — viewport-tight, the FIX).
    // This pixel scan corroborates: a CATASTROPHIC smear (the pre-fix 84 000px
    // slivers filling the frame) drives spoke_score toward ~1.0; a legit grazing
    // grid sits ~0.3–0.4 (real thin building edges / tri diagonals, confirmed by
    // eye). 0.5 separates the two; both poses must clear it AND render real content.
    assert!(
        city.coverage > 0.005 && rabbit_pose.coverage > 0.02,
        "a pose rendered ~nothing (city cov={:.3}, close cov={:.3})",
        city.coverage,
        rabbit_pose.coverage
    );
    assert!(
        city.spoke_score < 0.5,
        "the worst-sweep city pose is a CATASTROPHIC spoke smear (spoke_score={:.3} ≥ 0.5)",
        city.spoke_score
    );
    assert!(
        rabbit_pose.spoke_score < 0.5,
        "the close-zoom pose is a CATASTROPHIC spoke smear (spoke_score={:.3} ≥ 0.5)",
        rabbit_pose.spoke_score
    );
    let _ = Color32::WHITE;
}