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/region_span_buildings_rise.rs

//! **On a korp region viewport the houses must still count as houses.**
//!
//! `BUILDING_RISE_EPS` was an absolute design-unit constant (`4.0e-3`) deciding whether
//! a mesh vertex is a wall or a roof, while a building's rise is `height_m · du_per_m` —
//! metric, and therefore a function of how much ground the scene spans. Two unrelated
//! quantities, so which is bigger depends entirely on the viewport.
//!
//! MEASURED on the shipped korp path, a real focused Xvfb window (`:97`, 1900×1150,
//! `korp-ui --server` against the live korp-server, adapter NVIDIA GeForce RTX 4090
//! [discrete/Vulkan], `software=false`), Stockholm zoom 12.1, 2026-08-03:
//! `building_ways = 39 587`, `extruded_triangles = 2 123 768`, and
//! **`building_vertices = 0`, `buildings_visible = 0`** — two million triangles of
//! extruded city and not one vertex that counted as a building. `camera.distance` came
//! back `3.200000047683716`, bit-identical to the whole-mesh default, because
//! `frame_densest_cluster` took its `risen.len() < 3` early return: not THREE vertices
//! in Stockholm cleared even the looser `1e-3` the fitter used.
//!
//! Two definitions of "risen" in one file was the second half of it, and it hid the
//! first: the fitter asked `y > 1e-3`, every observable asked `y > BUILDING_RISE_EPS`,
//! so the camera and the oracles could disagree about whether the scene had buildings
//! in it — and on this data they did.
//!
//! Everything below asserts on APPLIED OUTPUT — the extruded mesh's own y coordinates,
//! the vertices that project inside the frustum at the framed pose — never on a knob
//! round-trip, and never on `camera.distance` alone (a number that sat on its default
//! and looked perfectly reasonable is precisely what hid this bug).

mod common;

use common::{region_with_town, ring, tags, M_PER_DEG_LAT, STOCKHOLM};
use facett_core::Theme;
use facett_map::Way;
use facett_map3d::{extrude, Map3D, BUILDING_RISE_EPS};

/// The measured korp z12 Stockholm viewport span.
const KORP_Z12_SPAN_M: f64 = 55_688.0;

/// **The defect, on the extruded mesh.** At korp's own measured region span the mesh
/// carries real risen building geometry, and the OLD absolute threshold could not see
/// any of it.
///
/// The second assert is the RED line: it pins that this fixture really is a scene where
/// the old constant reports zero, so the first assert is not passing on a scene that
/// would have worked anyway.
#[test]
fn a_region_scene_has_risen_buildings_the_absolute_threshold_could_not_see() {
    let ways = region_with_town(KORP_Z12_SPAN_M, 24);
    let span = extrude::world_span_metres(&ways).expect("a real world span");
    let du_per_m = extrude::DESIGN_FILL / span;
    assert!(
        (span - KORP_Z12_SPAN_M as f32).abs() / span < 0.05,
        "the fixture spans korp's measured viewport: {span:.0} m vs {KORP_Z12_SPAN_M:.0} m",
    );

    let map = Map3D::from_ways("region", &ways, 0.22);
    let eps = map.building_rise_eps();

    // APPLIED OUTPUT: the mesh's own vertices, counted by the scene's threshold.
    let risen = map.building_vertices();
    assert!(
        risen > 0,
        "span {span:.0} m, du_per_m {du_per_m:.3e}: {} building ways extruded and NOT ONE mesh \
         vertex counts as risen (threshold {eps:.4e})",
        ways.iter().filter(|w| w.kind == "building").count(),
    );

    // …and it counted them by the SCENE's threshold, derived from the scene's own span.
    let want = extrude::building_rise_eps(Some(du_per_m));
    assert!(
        (eps - want).abs() <= want * 1e-6,
        "the scene's rise threshold is derived from its own span: {eps:.4e} vs {want:.4e}",
    );


    // ── the RED line, spelled out ─────────────────────────────────────────────
    // With the old absolute constant this exact mesh reports zero. If this assert ever
    // fails the fixture has stopped being a region scene and the test above has stopped
    // proving anything.
    let by_absolute = map.mesh().positions.iter().filter(|p| p[1] > BUILDING_RISE_EPS).count();
    assert_eq!(
        by_absolute, 0,
        "NON-VACUITY: the old absolute BUILDING_RISE_EPS ({BUILDING_RISE_EPS:.1e}) must still see \
         nothing here — that is the defect this fixture reproduces",
    );

    // And by how much it missed: the tallest roof in the scene, against both thresholds.
    let ymax = map.mesh().positions.iter().fold(0.0f32, |a, p| a.max(p[1]));
    println!(
        "span {span:.0} m  du_per_m {du_per_m:.3e}  ymax {ymax:.4e}  \
         metric eps {eps:.4e} ({:.1}× under the roof)  absolute eps {BUILDING_RISE_EPS:.1e} \
         ({:.0}× OVER the roof)  risen vertices {risen}",
        ymax / eps,
        BUILDING_RISE_EPS / ymax,
    );
}

/// **The threshold still keeps the ground out.** The whole reason `BUILDING_RISE_EPS`
/// was set high was so a road-only scene reports zero buildings. A metric threshold has
/// to keep that guarantee at every span, and by construction rather than by luck: it is
/// floored above `ground_top`, the top of the scene's own ground band.
#[test]
fn no_road_or_cover_ever_counts_as_a_house_at_any_span() {
    let theme = Theme::default();
    for span_m in [300.0f64, 1_000.0, 3_000.0, 10_000.0, KORP_Z12_SPAN_M, 200_000.0] {
        // The same region, with every building way removed.
        let ground: Vec<Way> = region_with_town(span_m, 24).into_iter().filter(|w| w.kind != "building").collect();
        assert!(!ground.is_empty(), "span {span_m}: the ground-only scene must still have features");
        let map = Map3D::from_ways("ground only", &ground, 0.22);
        assert_eq!(
            map.building_vertices(),
            0,
            "span {span_m} m: a scene of roads, water and forest reported {} risen 'building' \
             vertices at threshold {:.4e}",
            map.building_vertices(),
            map.building_rise_eps(),
        );

        // …and the margin, measured: the highest ground vertex in the mesh vs the threshold.
        let gmax = map.mesh().positions.iter().fold(0.0f32, |a, p| a.max(p[1]));
        assert!(
            gmax > 0.0,
            "span {span_m} m: the ground layers must still clear the terrain plane (else this \
             passes vacuously — a band collapsed to zero is not a band)",
        );
        assert!(
            gmax < map.building_rise_eps(),
            "span {span_m} m: the ground reaches {gmax:.4e}, at or over the rise threshold {:.4e}",
            map.building_rise_eps(),
        );

        // The shortest building the extruder can emit must clear it at the same span —
        // both halves of "cover < road < roof", on one scale.
        let full = region_with_town(span_m, 4);
        let stats = extrude::building_height_stats(&full, 0.22);
        let eps_full = extrude::building_rise_eps_for(&full);
        assert!(
            stats.min > eps_full,
            "span {span_m} m: the SHORTEST roof ({:.4e}) does not clear the rise threshold \
             ({eps_full:.4e})",
            stats.min,
        );
        // A theme-suppressing check that the fixture really produced buildings.
        assert!(stats.buildings > 0, "span {span_m} m: the fixture extruded no buildings");
        let _ = &theme;
    }
}

/// **The camera fitter fires, and it fires on the SAME definition of "risen".**
///
/// `frame_densest_cluster` used its own hardcoded `1e-3`. On a region viewport that was
/// above every real rooftop, so the fitter early-returned and left the camera on its
/// whole-box default over a scene that was nothing but city — the "huge empty ground
/// plane with the town as a thumbnail" a korp user sees.
///
/// The oracle here is NOT `camera.distance` (the number that sat on `3.2` and looked
/// fine). It is `city_framing()`, which is `None` until the fitter actually ran, plus
/// `buildings_visible()` — vertices PROJECTED through the live render camera and found
/// inside the frustum, i.e. houses genuinely in shot.
#[test]
fn the_camera_fitter_finds_the_town_in_a_region_scene() {
    let ways = region_with_town(KORP_Z12_SPAN_M, 24);
    let mut map = Map3D::from_ways("region", &ways, 0.22);

    assert!(map.city_framing().is_none(), "a fresh from_ways has not framed anything yet");
    let default_dist = map.render_camera().distance;

    map.frame_densest_cluster();

    let framing = map
        .city_framing()
        .expect("the fitter must have found the town — None means it took the risen.len() < 3 return");
    let dist = map.render_camera().distance;
    // The fitter's OWN published centroid — the cluster it actually landed on.
    let target = framing.center;

    // It moved, and it moved ONTO the town — not merely to some other number. The town
    // sits a third of the way toward the NE corner, so both design-plane coordinates
    // must be positive and well off the origin the default pose looks at.
    assert!(
        target.x > 0.1 && target.z < -0.1,
        "the camera targets the off-centre town (design +x, north = −z): target = \
         ({:.3}, {:.3}, {:.3})",
        target.x,
        target.y,
        target.z,
    );
    assert!(
        dist < default_dist,
        "the fitter dollies IN on the town: {dist:.4} vs the default {default_dist:.4}",
    );
    assert!(framing.extent > 0.0, "the framing carries a real town extent: {:?}", framing.extent);

    // APPLIED OUTPUT: at the framed pose, real building vertices project inside the
    // viewport. This is the assert `camera.distance` could never make.
    let visible = map.buildings_visible();
    assert!(
        visible > 0,
        "the framed camera has no houses in shot ({} risen vertices exist in the mesh)",
        map.building_vertices(),
    );
    println!(
        "framed: target ({:.3}, {:.3}, {:.3})  distance {dist:.4} (default {default_dist:.4})  \
         extent {:.4}  buildings_visible {visible} / {} risen",
        target.x,
        target.y,
        target.z,
        framing.extent,
        map.building_vertices(),
    );
}

/// **One quantity, one writer.** Every risen-geometry question in `Map3D` must answer
/// from the SAME threshold — that is the whole LAW-5 half of this defect. Proven by
/// construction: a scene built so that the metric threshold and the old absolute one
/// disagree must have every observable on the metric side of the split.
#[test]
fn every_risen_geometry_observable_uses_the_one_threshold() {
    let ways = region_with_town(KORP_Z12_SPAN_M, 24);
    let mut map = Map3D::from_ways("region", &ways, 0.22);
    map.frame_densest_cluster();

    let eps = map.building_rise_eps();
    assert!(eps < BUILDING_RISE_EPS, "the split this test needs: {eps:.4e} < {BUILDING_RISE_EPS:.1e}");

    // `building_vertices` is the threshold applied to the raw mesh — recompute it here
    // independently and require the API to agree.
    let by_hand = map.mesh().positions.iter().filter(|p| p[1] > eps).count();
    assert_eq!(map.building_vertices(), by_hand, "building_vertices counts by the scene threshold");
    assert!(by_hand > 0, "…and there is something to count");

    // `buildings_visible` is a strict subset (frustum-culled) and non-empty at the pose.
    let visible = map.buildings_visible();
    assert!(visible > 0 && visible <= by_hand, "visible {visible} of {by_hand} risen");

    // `flanking_houses` reads the same set through the camera basis.
    let (l, r) = map.flanking_houses();
    assert!(l + r > 0, "the flanking-house oracle sees the same risen set (left {l}, right {r})");

    // The roof accent recolours only caps ABOVE the same threshold — applied output is
    // the mesh's own colour buffer, so compare against an un-accented twin.
    let plain = Map3D::from_ways("region", &ways, 0.22);
    let accented = Map3D::from_ways("region", &ways, 0.22).with_roof_accent(0.6);
    let lum = |c: egui::Color32| c.r() as u32 + c.g() as u32 + c.b() as u32;
    let changed = (0..plain.mesh().triangle_count())
        .filter(|&t| lum(accented.mesh().colors[t]) != lum(plain.mesh().colors[t]))
        .count();
    assert!(
        changed > 0,
        "the roof accent brightened NO triangle — it bailed on `ymax <= eps` exactly like the \
         observables did, which is what one shared threshold is for",
    );
}

/// The threshold function itself: metric where there is a metre, the legacy absolute
/// value where there is not, and never down inside the ground band.
///
/// The `None` arm is what keeps every synthetic fixture (the rabbit, the unit-test
/// towns) reporting byte-for-byte the same counts as before.
#[test]
fn the_rise_threshold_is_metric_where_there_is_a_metre() {
    assert_eq!(
        extrude::building_rise_eps(None),
        BUILDING_RISE_EPS,
        "no world scale ⇒ the legacy absolute threshold, so synthetic scenes do not move",
    );
    assert_eq!(extrude::building_rise_eps(Some(0.0)), BUILDING_RISE_EPS, "a degenerate scale is no scale");

    // The ground half holds at EVERY span, without exception — that is the guarantee
    // the floor exists for, and it is unconditional.
    for span_m in [300.0f32, 1_000.0, 3_000.0, 10_000.0, 55_688.0, 200_000.0, 1_000_000.0] {
        let dpm = extrude::DESIGN_FILL / span_m;
        let eps = extrude::building_rise_eps(Some(dpm));
        let top = extrude::ground_top(extrude::ground_band(Some(dpm)));
        assert!(
            eps > top,
            "span {span_m} m: the rise threshold {eps:.4e} must sit clear of the top of the \
             ground band {top:.4e}, or a road ribbon is a house",
        );
    }

    // The building half holds up to the documented bound and NOT past it. Both sides are
    // asserted, so the bound is MEASURED here rather than claimed in a doc comment.
    for span_m in [300.0f32, 1_000.0, 3_000.0, 10_000.0, 55_688.0, 200_000.0, 270_000.0] {
        let dpm = extrude::DESIGN_FILL / span_m;
        let eps = extrude::building_rise_eps(Some(dpm));
        assert!(
            eps < extrude::MIN_DEFAULT_BUILDING_HEIGHT_M * dpm,
            "span {span_m} m: the threshold {eps:.4e} must stay under the SHORTEST building the \
             extruder can emit ({:.4e}), or a real house is ground",
            extrude::MIN_DEFAULT_BUILDING_HEIGHT_M * dpm,
        );
    }
    for span_m in [275_000.0f32, 1_000_000.0] {
        let dpm = extrude::DESIGN_FILL / span_m;
        assert!(
            extrude::building_rise_eps(Some(dpm)) > extrude::MIN_DEFAULT_BUILDING_HEIGHT_M * dpm,
            "span {span_m} m is supposed to be OUTSIDE the honest bound — if this now passes the \
             bound has moved and the doc on `building_rise_eps` is stale",
        );
    }

    // Inside the bound (span ≤ ~110 km) the threshold IS the metric conversion — it
    // means "one metre", not "a bit above the kerb".
    for span_m in [300.0f32, 3_000.0, 55_688.0] {
        let dpm = extrude::DESIGN_FILL / span_m;
        let eps = extrude::building_rise_eps(Some(dpm));
        let metric = extrude::BUILDING_RISE_METRES * dpm;
        assert!(
            (eps - metric).abs() <= metric * 1e-6,
            "span {span_m} m: inside the honest bound the threshold is exactly {metric:.4e} \
             (one metre), got {eps:.4e}",
        );
    }
}

/// A **flat** synthetic scene still reports zero — the guard the old constant was really
/// there for, on the path that keeps the absolute value.
#[test]
fn a_scene_with_no_world_scale_keeps_the_legacy_threshold() {
    // A single degenerate way: no span the extruder can measure ⇒ `du_per_m == None`.
    let theme = Theme::default();
    let (clon, clat) = STOCKHOLM;
    let tiny = 0.2 / M_PER_DEG_LAT; // a 40 cm ring — under the 1 m span floor
    let ways: Vec<Way> = Way::from_lonlat(1, &ring(clon, clat, tiny, tiny), &tags(&[("building", "yes")]), &theme).into_iter().collect();
    assert!(!ways.is_empty());
    assert!(
        extrude::world_span_metres(&ways).is_none(),
        "the fixture must genuinely have no measurable world span",
    );
    let map = Map3D::from_ways("scale-free", &ways, 0.22);
    assert_eq!(
        map.building_rise_eps(),
        BUILDING_RISE_EPS,
        "a scene with no metres keeps the absolute threshold, so synthetic goldens do not move",
    );
}

/// **The legibility oracle must not be blind.**
///
/// `buildings_visible` counts vertices inside the frustum. On the shipped korp path it
/// reported 340 581 houses in shot over a pane that drew a flat white pancake — a green
/// that could never go red for the thing a user complains about, because the houses were
/// 0.66 px tall. `skyline_screen_height_px` is the number that reads flat when the pane
/// looks flat, and this pins that it actually distinguishes the two cases rather than
/// returning something plausible in both.
#[test]
fn the_legibility_oracle_tells_a_pancake_from_a_town() {
    // A REGION viewport: the town is a 1 km speck in a 55.7 km scene.
    let region = region_with_town(KORP_Z12_SPAN_M, 24);
    let mut wide = Map3D::from_ways("region", &region, 0.22);
    wide.frame_densest_cluster();
    let wide_px = wide.skyline_screen_height_px(1000.0);

    // The SAME houses, extruded as their own town (a 1.5 km scene) — the scale the
    // subset path produces.
    let town = region_with_town(1_500.0, 24);
    let mut close = Map3D::from_ways("town", &town, 0.22);
    close.frame_densest_cluster();
    let close_px = close.skyline_screen_height_px(1000.0);

    // Both scenes are full of houses BY THE COUNT — that is the point.
    assert!(wide.buildings_visible() > 1_000, "the region pane has houses in shot: {}", wide.buildings_visible());
    assert!(close.buildings_visible() > 1_000, "the town pane has houses in shot: {}", close.buildings_visible());

    // …and only one of them shows any.
    assert!(
        wide_px < 3.0,
        "the region pane must READ FLAT — that is the defect this oracle exists to see, \
         got {wide_px:.2} px",
    );
    assert!(
        close_px >= 3.0,
        "the town pane must read as buildings, got {close_px:.2} px",
    );
    assert!(
        close_px > wide_px * 5.0,
        "the oracle must SEPARATE the two, not merely rank them: town {close_px:.2} px vs \
         region {wide_px:.2} px",
    );
    println!("legibility: region {wide_px:.2} px  town {close_px:.2} px  \
              (visible {} vs {})", wide.buildings_visible(), close.buildings_visible());

    // NON-VACUITY: an empty pane reads 0, so a scene with nothing risen cannot be
    // mistaken for a legible one.
    let ground: Vec<Way> = region_with_town(KORP_Z12_SPAN_M, 24).into_iter().filter(|w| w.kind != "building").collect();
    let flat = Map3D::from_ways("ground only", &ground, 0.22);
    assert_eq!(flat.skyline_screen_height_px(1000.0), 0.0, "no risen geometry ⇒ no skyline");
}

/// **The town window must bound the GEOMETRY, not merely choose it.**
///
/// `densest_cluster_subset` finds the town correctly and then used to return every way
/// that *touched* the window, whole — so a single trunk road running out of the window
/// put the retained bbox, and with it the scene's design unit, straight back at region
/// scale. MEASURED on the shipped korp path (2026-08-03, Stockholm z12, live server):
/// the subset cut 2 802 173 triangles to 116 465 — it HAD found the town — while
/// `metres_per_design_unit` stayed at **33 195**, a 33 km design unit on a 3 km window,
/// and the median house still stood 0.43 px.
#[test]
fn the_town_subset_bounds_the_scene_scale() {
    let region = region_with_town(KORP_Z12_SPAN_M, 24);
    let region_span = extrude::world_span_metres(&region).expect("a region span");
    assert!(region_span > 50_000.0, "the fixture is region-scale: {region_span:.0} m");

    let town = extrude::densest_cluster_subset(&region);
    let town_span = extrude::world_span_metres(&town).expect("the town has a span");

    // The window is ±1500 m, so a bounded subset spans at most ~3 km. Allow the
    // diagonal; what must NOT happen is the span staying region-sized.
    assert!(
        town_span < 5_000.0,
        "the subset must be TOWN-scale — got {town_span:.0} m out of a {region_span:.0} m \
         region. A way reaching out of the window is still setting the scene scale.",
    );

    // …and it is still a town, not a crumb: the houses survived, and so did the part of
    // the trunk road that crosses them (clipped, not deleted).
    let houses = town.iter().filter(|w| w.kind == "building").count();
    assert!(houses > 100, "the town kept its buildings, got {houses}");
    let roads = town.iter().filter(|w| w.kind == "road").count();
    assert!(roads > 0, "the street through the town survived the clip");
    for w in town.iter() {
        assert!(!w.lonlat.is_empty(), "no way is left with an empty geometry");
        assert_eq!(w.points.len(), w.lonlat.len(), "clipping kept points and lonlat in step");
    }

    // APPLIED OUTPUT: what the scale is FOR — a legible house.
    let mut map = Map3D::from_geometry("town", &region);
    map.frame_densest_cluster();
    let px = map.skyline_screen_height_px(1000.0);
    assert!(
        px >= 3.0,
        "the whole point of the subset is a house you can see: {px:.2} px on a 1000 px pane",
    );
    println!(
        "subset: {region_span:.0} m / {} ways -> {town_span:.0} m / {} ways  \
         ({houses} houses, {roads} roads)  skyline {px:.2} px  m/du {:.0}",
        region.len(),
        town.len(),
        map.metres_per_design_unit(),
    );
}