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

//! **Sigtuna tour proof** (headless, data-level — no pixels, no GPU).
//!
//! The demo brief is a cinematic autopilot over the extruded OSM town: start HIGH
//! circling the houses from the air, DESCEND (bird → street), then DRIVE down the
//! streets. This asserts, as DATA read back off the live `Map3D` render camera:
//!   1. attaching the tour makes it ACTIVE and it walks Circle → Descend → Drive as
//!      the clock advances (`state_json.tour_phase`),
//!   2. the camera genuinely DESCENDS — the render camera pulls far CLOSER in for the
//!      drive than it sat for the air circle (bird → street),
//!   3. the air phase ORBITS (the render azimuth advances over the circle), and
//!   4. it's deterministic under a pinned clock (FC-7): same clock ⇒ same pose.
//!
//! No window: drives `Map3D` through `set_clock` + `render_camera` + `state_json`.
//!
//! Run: `cargo test -p facett-map3d --test sigtuna_tour_proof [--features testmatrix]`.

use facett_core::Facet; // brings `state_json()` into scope
use facett_map3d::{Map3D, TourPhase};

/// A tiny synthetic town (a filled building ring + a road line) so the tour has a
/// framed city + a followable street, without any fixture on disk.
fn town() -> Vec<facett_map::Way> {
    use egui::Color32;
    let fill = Color32::from_rgb(120, 160, 210);
    let outline = Color32::from_rgb(30, 50, 70);
    // Two building blocks so `frame_densest_cluster` has a real footprint.
    let b1 = facett_map::Way::filled(
        1,
        "building",
        vec![(9.500, 47.100), (9.502, 47.100), (9.502, 47.102), (9.500, 47.102), (9.500, 47.100)],
        fill,
        outline,
        1.0,
    );
    let b2 = facett_map::Way::filled(
        2,
        "building",
        vec![(9.504, 47.101), (9.506, 47.101), (9.506, 47.103), (9.504, 47.103), (9.504, 47.101)],
        fill,
        outline,
        1.0,
    );
    // A road running across the town — the street the drive phase follows.
    let road = facett_map::Way::line(
        3,
        "highway",
        vec![(9.499, 47.1005), (9.503, 47.1015), (9.506, 47.1025)],
        Color32::from_rgb(70, 78, 90),
        2.0,
    );
    vec![b1, b2, road]
}

/// The waypoint chain (a road's `Way::points`, Mercator-unit) the route follows.
fn street_waypoints(ways: &[facett_map::Way]) -> Vec<(f32, f32)> {
    ways.iter()
        .find(|w| w.kind.contains("highway"))
        .map(|w| w.points.clone())
        .unwrap_or_default()
}

#[test]
fn sigtuna_tour_circles_descends_and_drives() {
    let ways = town();
    let wps = street_waypoints(&ways);
    assert!(wps.len() >= 2, "the town has a followable street ({} waypoints)", wps.len());

    let mut map = Map3D::from_geometry("Sigtuna tour", &ways).with_route(&ways, &wps).with_tour(true);

    // Buildings actually extruded (houses visible): the mesh rose off the ground plane.
    let raised = map.mesh().positions.iter().any(|p| p[1] > 0.02);
    assert!(raised, "the town's buildings extrude into 3D prisms (a raised mesh vertex)");
    assert!(map.tour_active(), "attaching the tour makes it active");
    assert!(map.has_route(), "the drive phase has a street route to follow");

    // (1) Walk the clock across a full loop; collect the phase + render-camera pose.
    let total = 18.0 + 8.0 + 26.0; // circle + descend + drive (SigtunaTour defaults)
    let mut saw_circle = false;
    let mut saw_descend = false;
    let mut saw_drive = false;
    let mut air_dist = 0.0f32; // camera distance mid-air-circle
    let mut street_dist = f32::INFINITY; // camera distance mid-drive
    let mut az_start = 0.0f32;
    let mut az_mid_air = 0.0f32;
    // Keyframe altitude (metres) + houses-in-frame at the two ends of the descent.
    let mut air_alt_m = 0.0f32; // altitude mid air-circle (HIGH)
    let mut street_alt_m = f32::INFINITY; // altitude mid drive (LOW)
    let mut circle_buildings = 0usize; // risen houses in frame at the circle altitude
    let samples = 120;
    for i in 0..=samples {
        let t = i as f64 * total / samples as f64;
        map.set_clock(t);
        let phase = map.tour_phase().expect("tour is active → a phase");
        let cam = map.render_camera();
        match phase {
            TourPhase::Circle => {
                saw_circle = true;
                if t < 1.0 {
                    az_start = cam.azimuth;
                }
                if (t - 12.0).abs() < 1.0 {
                    az_mid_air = cam.azimuth;
                    air_dist = cam.distance;
                    air_alt_m = map.altitude_m();
                    circle_buildings = circle_buildings.max(map.buildings_visible());
                }
            }
            TourPhase::Descend => saw_descend = true,
            TourPhase::Drive => {
                saw_drive = true;
                street_dist = street_dist.min(cam.distance);
                street_alt_m = street_alt_m.min(map.altitude_m());
            }
        }
    }

    assert!(saw_circle && saw_descend && saw_drive, "the tour walks Circle → Descend → Drive across the loop");

    // (KEYFRAME) The camera opens HIGH and ends LOW: the metric altitude mid air-circle
    // is far above the altitude mid street-drive — the "overview → down the streets"
    // arc the brief asks for, read straight off the calibrated `altitude_m`.
    let descended_altitude = air_alt_m > street_alt_m * 2.0;
    assert!(
        descended_altitude,
        "the tour opens high then drops to street level (air {air_alt_m:.0} m ≫ street {street_alt_m:.0} m)"
    );
    // (HOUSES) At the air-circle altitude the extruded houses are IN FRAME — the whole
    // point of circling Sigtuna ("we want to SEE THE HOUSES"). RED-when-broken: a scene
    // whose buildings don't extrude reports 0 here (see the lib `buildings_visible` gate).
    assert!(circle_buildings > 0, "houses are visible at the air-circle altitude ({circle_buildings} risen verts in frame)");

    // (2) It DESCENDS: the drive pulls far closer in than the air circle sat.
    assert!(
        air_dist > street_dist + 0.5,
        "the tour descends bird → street (air dist {air_dist} ≫ street dist {street_dist})"
    );

    // (3) The air phase ORBITS: azimuth advanced from the start of the circle to mid-air.
    let orbited = (az_mid_air - az_start).abs() > 0.1;
    assert!(orbited, "the air circle orbits the skyline (az {az_start} → {az_mid_air})");

    // (4) Determinism (FC-7): the same pinned clock replays the identical pose.
    map.set_clock(30.0);
    let a = map.render_camera();
    map.set_clock(30.0);
    let b = map.render_camera();
    let deterministic = a.eye() == b.eye() && a.azimuth == b.azimuth && a.distance == b.distance;
    assert!(deterministic, "the tour pose is a pure function of the clock");

    // The state_json oracle surfaces the tour for a robot-UI / mega-matrix to assert.
    map.set_clock(2.0);
    let sj = map.state_json();
    assert_eq!(sj["tour_active"], serde_json::json!(true), "state_json exposes tour_active");
    assert_eq!(sj["tour_phase"], serde_json::json!("circle"), "state_json exposes the live phase");

    #[cfg(feature = "testmatrix")]
    {
        let ok = saw_circle
            && saw_descend
            && saw_drive
            && air_dist > street_dist + 0.5
            && orbited
            && deterministic
            && raised
            && descended_altitude
            && circle_buildings > 0;
        facett_core::testmatrix::emit(
            "facett-map3d",
            "sigtuna_tour_circle_descend_drive",
            ok,
            &format!(
                "raised={raised} circle={saw_circle} descend={saw_descend} drive={saw_drive} \
                 air_dist={air_dist:.3} street_dist={street_dist:.3} orbited={orbited} det={deterministic} \
                 air_alt_m={air_alt_m:.0} street_alt_m={street_alt_m:.0} circle_buildings={circle_buildings}"
            ),
        );
    }
}