oxiproj-engine 0.1.2

Proj-string parser, operation dispatch, and transformation pipelines for OxiProj.
Documentation
use oxiproj_core::{Coord, Direction, DEG_TO_RAD};
use oxiproj_engine::{create, trans};

#[test]
fn cc_differential_vs_proj() {
    let pj = create("+proj=cc +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.209439510239_f64, 1.428148006742_f64),
        (-30.0, -20.0, -std::f64::consts::FRAC_PI_6, -0.363970234266),
        (40.0, 0.0, 0.698131700798, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} vs {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} vs {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} vs {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} vs {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn tcc_differential_vs_proj() {
    let pj = create("+proj=tcc +R=1").unwrap();
    let lon_rad = 20.0_f64 * DEG_TO_RAD;
    let lat_rad = 40.0_f64 * DEG_TO_RAD;
    let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
    assert!(
        (fwd.v()[0] - 0.271_486_422_197_f64).abs() < 1e-6,
        "x {} vs 0.271486422197",
        fwd.v()[0]
    );
    assert!(
        (fwd.v()[1] - 0.728_907_046_429_f64).abs() < 1e-6,
        "y {} vs 0.728907046429",
        fwd.v()[1]
    );
}

#[test]
fn tobmerc_differential_against_proj_sphere() {
    let pj = create("+proj=tobmerc +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.068903489465_f64, 1.154234553609_f64),
        (-30.0, -20.0, -0.462349354035, -0.356378504724),
        (40.0, 0.0, 0.698131700798, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} != {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} != {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} != {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} != {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn tobmerc_differential_against_proj_wgs84() {
    let pj = create("+proj=tobmerc +ellps=WGS84").unwrap();
    let rows = [
        (
            12.0_f64,
            55.0_f64,
            439_475.895_583_306_f64,
            7361866.113051188_f64,
        ),
        (-30.0, -20.0, -2948927.521894425, -2273030.9269876895),
        (40.0, 0.0, 4452779.631730943, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-3,
            "x {} != {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-3,
            "y {} != {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} != {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} != {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn times_differential_against_proj() {
    let pj = create("+proj=times +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64),
        (-30.0_f64, -20.0_f64),
        (40.0_f64, 0.0_f64),
    ];
    for &(lon_deg, lat_deg) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            fwd.v()[0].is_finite(),
            "x must be finite at ({lon_deg}, {lat_deg})"
        );
        assert!(
            fwd.v()[1].is_finite(),
            "y must be finite at ({lon_deg}, {lat_deg})"
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} vs {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} vs {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn gall_differential_vs_proj() {
    let pj = create("+proj=gall +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.148096097939_f64, 0.888663542059_f64),
        (-30.0, -20.0, -0.370240244847, -0.301008984474),
        (40.0, 0.0, 0.493653659795, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} vs {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} vs {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} vs {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} vs {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn comill_differential_against_proj() {
    let pj = create("+proj=comill +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.209439510239_f64, 1.067512314124_f64),
        (-30.0, -20.0, -std::f64::consts::FRAC_PI_6, -0.352308963946),
        (40.0, 0.0, 0.698131700798, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} != {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} != {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} != {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} != {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn mill_differential_vs_proj() {
    let pj = create("+proj=mill +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.209439510239_f64, 1.071128250954_f64),
        (-30.0, -20.0, -std::f64::consts::FRAC_PI_6, -0.353693164293),
        (40.0, 0.0, 0.698131700798, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} vs {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} vs {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} vs {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} vs {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn ocea_differential_vs_proj() {
    let pj = create("+proj=ocea +R=1 +lat_1=30 +lon_1=0 +lat_2=60 +lon_2=90").unwrap();
    let lon_rad = 30.0_f64 * DEG_TO_RAD;
    let lat_rad = 50.0_f64 * DEG_TO_RAD;
    let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
    assert!(
        (fwd.v()[0] - 2.012_067_364_318_f64).abs() < 1e-6,
        "x {} vs 2.012067364318",
        fwd.v()[0]
    );
    assert!(
        (fwd.v()[1] - 0.053_812_552_532_f64).abs() < 1e-6,
        "y {} vs 0.053812552532",
        fwd.v()[1]
    );
    let inv = trans(&pj, Direction::Inv, fwd).unwrap();
    assert!(
        (inv.v()[0] - lon_rad).abs() < 1e-9,
        "inv lon {} vs {lon_rad}",
        inv.v()[0]
    );
    assert!(
        (inv.v()[1] - lat_rad).abs() < 1e-9,
        "inv lat {} vs {lat_rad}",
        inv.v()[1]
    );
}

#[test]
fn patterson_differential_against_proj() {
    let pj = create("+proj=patterson +R=1").unwrap();
    let rows = [
        (12.0_f64, 55.0_f64, 0.209439510239_f64, 1.070868358912_f64),
        (-30.0, -20.0, -std::f64::consts::FRAC_PI_6, -0.355343875358),
        (40.0, 0.0, 0.698131700798, 0.0),
    ];
    for &(lon_deg, lat_deg, expected_x, expected_y) in &rows {
        let lon_rad = lon_deg * DEG_TO_RAD;
        let lat_rad = lat_deg * DEG_TO_RAD;
        let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
        assert!(
            (fwd.v()[0] - expected_x).abs() < 1e-6,
            "x {} != {expected_x}",
            fwd.v()[0]
        );
        assert!(
            (fwd.v()[1] - expected_y).abs() < 1e-6,
            "y {} != {expected_y}",
            fwd.v()[1]
        );
        let inv = trans(&pj, Direction::Inv, fwd).unwrap();
        assert!(
            (inv.v()[0] - lon_rad).abs() < 1e-9,
            "lon {} != {lon_rad}",
            inv.v()[0]
        );
        assert!(
            (inv.v()[1] - lat_rad).abs() < 1e-9,
            "lat {} != {lat_rad}",
            inv.v()[1]
        );
    }
}

#[test]
fn tcea_differential_vs_proj() {
    let pj = create("+proj=tcea +R=1").unwrap();
    let lon_rad = 20.0_f64 * DEG_TO_RAD;
    let lat_rad = 40.0_f64 * DEG_TO_RAD;
    let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0)).unwrap();
    assert!(
        (fwd.v()[0] - 0.262_002_630_229_f64).abs() < 1e-6,
        "x {} vs 0.262002630229",
        fwd.v()[0]
    );
    assert!(
        (fwd.v()[1] - 0.728_907_046_429_f64).abs() < 1e-6,
        "y {} vs 0.728907046429",
        fwd.v()[1]
    );
    let inv = trans(&pj, Direction::Inv, fwd).unwrap();
    assert!(
        (inv.v()[0] - lon_rad).abs() < 1e-9,
        "inv lon {} vs {lon_rad}",
        inv.v()[0]
    );
    assert!(
        (inv.v()[1] - lat_rad).abs() < 1e-9,
        "inv lat {} vs {lat_rad}",
        inv.v()[1]
    );
}