aerocontext-core 0.4.2

Provider-neutral aeronautical-context model and the pluggable ContextProvider contract
Documentation
use super::*;

const JFK: GeoPoint = GeoPoint {
    lat: 40.639928,
    lon: -73.778692,
};
const LAX: GeoPoint = GeoPoint {
    lat: 33.942536,
    lon: -118.408075,
};

#[test]
fn jfk_to_lax_great_circle_matches_published_values() {
    // Published great-circle distance ≈ 2,144 NM; initial bearing ≈ 274°.
    let distance = distance_nm(JFK, LAX);
    assert!(
        (distance - 2144.0).abs() < 5.0,
        "distance {distance} NM should be ≈2144"
    );
    let bearing = initial_bearing_deg(JFK, LAX);
    assert!(
        (bearing - 274.0).abs() < 1.5,
        "bearing {bearing}° should be ≈274"
    );
}

#[test]
fn destination_round_trips_distance_and_bearing() {
    let bearing = initial_bearing_deg(JFK, LAX);
    let leg = distance_nm(JFK, LAX);
    let reached = destination(JFK, bearing, leg);
    assert!(
        distance_nm(reached, LAX) < 1.0,
        "great-circle destination lands within 1 NM of LAX"
    );
}

#[test]
fn cross_track_sign_distinguishes_sides() {
    // A north-up leg along the prime meridian; points east are right
    // (positive), west are left (negative).
    let start = GeoPoint { lat: 0.0, lon: 0.0 };
    let end = GeoPoint {
        lat: 10.0,
        lon: 0.0,
    };
    let east = GeoPoint { lat: 5.0, lon: 1.0 };
    let west = GeoPoint {
        lat: 5.0,
        lon: -1.0,
    };
    assert!(cross_track_nm(east, start, end) > 0.0);
    assert!(cross_track_nm(west, start, end) < 0.0);
    // One degree of longitude at the equator ≈ 60 NM.
    assert!((cross_track_nm(east, start, end) - 60.0).abs() < 1.0);
}

#[test]
fn along_track_measures_projection() {
    let start = GeoPoint { lat: 0.0, lon: 0.0 };
    let end = GeoPoint {
        lat: 10.0,
        lon: 0.0,
    };
    let abeam_5n = GeoPoint { lat: 5.0, lon: 1.0 };
    let along = along_track_nm(abeam_5n, start, end);
    // 5° of latitude ≈ 300 NM along the leg.
    assert!((along - 300.0).abs() < 2.0, "along {along}");
}

#[test]
fn longitude_normalization_wraps() {
    assert!((normalize_lon(190.0) - -170.0).abs() < 1e-9);
    assert!((normalize_lon(-190.0) - 170.0).abs() < 1e-9);
    assert!((normalize_lon(360.0) - 0.0).abs() < 1e-9);
    assert!((normalize_lon(180.0) - 180.0).abs() < 1e-9);
}

#[test]
fn along_track_is_negative_behind_the_start() {
    let start = GeoPoint { lat: 5.0, lon: 0.0 };
    let end = GeoPoint {
        lat: 10.0,
        lon: 0.0,
    };
    let behind = GeoPoint { lat: 4.0, lon: 0.0 };
    let along = along_track_nm(behind, start, end);
    assert!(along < 0.0, "behind-the-start projects negative: {along}");
    assert!((along + 60.0).abs() < 1.0, "≈1° of latitude behind");
}