use oxiproj_core::{Coord, Direction, DEG_TO_RAD};
use oxiproj_engine::{create, trans};
fn assert_close(got: f64, expected: f64, tol: f64, what: &str) {
let diff = (got - expected).abs();
assert!(
diff < tol,
"{what}: got {got}, expected {expected}, abs diff {diff} >= tol {tol}",
);
}
fn check_fwd_inv(proj: &str, lon_deg: f64, lat_deg: f64, ex: f64, ey: f64, fwd_tol: f64) {
let lon_rad = lon_deg * DEG_TO_RAD;
let lat_rad = lat_deg * DEG_TO_RAD;
let pj = create(proj).unwrap_or_else(|e| panic!("create {proj}: {e:?}"));
let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0))
.unwrap_or_else(|e| panic!("forward {proj}: {e:?}"));
assert_close(fwd.v()[0], ex, fwd_tol, &format!("{proj} forward x"));
assert_close(fwd.v()[1], ey, fwd_tol, &format!("{proj} forward y"));
let inv = trans(&pj, Direction::Inv, fwd).unwrap_or_else(|e| panic!("inverse {proj}: {e:?}"));
assert_close(inv.v()[0], lon_rad, 1e-9, &format!("{proj} inverse lon"));
assert_close(inv.v()[1], lat_rad, 1e-9, &format!("{proj} inverse lat"));
}
fn check_fwd(proj: &str, lon_deg: f64, lat_deg: f64, ex: f64, ey: f64, fwd_tol: f64) {
let lon_rad = lon_deg * DEG_TO_RAD;
let lat_rad = lat_deg * DEG_TO_RAD;
let pj = create(proj).unwrap_or_else(|e| panic!("create {proj}: {e:?}"));
let fwd = trans(&pj, Direction::Fwd, Coord::new(lon_rad, lat_rad, 0.0, 0.0))
.unwrap_or_else(|e| panic!("forward {proj}: {e:?}"));
assert_close(fwd.v()[0], ex, fwd_tol, &format!("{proj} forward x"));
assert_close(fwd.v()[1], ey, fwd_tol, &format!("{proj} forward y"));
}
#[test]
fn vandg_forward_and_inverse() {
check_fwd_inv(
"+proj=vandg +R=1",
20.0,
30.0,
0.338871219566,
0.540093568707,
1e-6,
);
check_fwd_inv(
"+proj=vandg +R=1",
-120.0,
-40.0,
-1.997264619583,
-0.807286748096,
1e-6,
);
}
#[test]
fn vandg2_forward() {
check_fwd(
"+proj=vandg2 +R=1",
20.0,
30.0,
0.338667231749,
0.545468319880,
1e-6,
);
check_fwd(
"+proj=vandg2 +R=1",
-120.0,
-40.0,
-1.932092470873,
-1.038468500057,
1e-6,
);
}
#[test]
fn vandg3_forward() {
check_fwd(
"+proj=vandg3 +R=1",
20.0,
30.0,
0.338912020660,
0.539012084453,
1e-6,
);
check_fwd(
"+proj=vandg3 +R=1",
-120.0,
-40.0,
-2.013749455508,
-0.736501042227,
1e-6,
);
}
#[test]
fn vandg4_forward() {
check_fwd(
"+proj=vandg4 +R=1",
20.0,
30.0,
0.311665090508,
0.525382626635,
1e-6,
);
check_fwd(
"+proj=vandg4 +R=1",
-120.0,
-40.0,
-1.869031720677,
-0.828680450024,
1e-6,
);
}
#[test]
fn bacon_forward() {
check_fwd(
"+proj=bacon +R=1",
20.0,
30.0,
0.264952224901,
std::f64::consts::FRAC_PI_4,
1e-6,
);
check_fwd(
"+proj=bacon +R=1",
-120.0,
-40.0,
-1.745716730077,
-1.009688416205,
1e-6,
);
}
#[test]
fn apian_forward() {
check_fwd(
"+proj=apian +R=1",
20.0,
30.0,
0.311919918291,
std::f64::consts::FRAC_PI_6,
1e-6,
);
check_fwd(
"+proj=apian +R=1",
-120.0,
-40.0,
-1.937984618661,
-0.698131700798,
1e-6,
);
}
#[test]
fn ortel_forward() {
check_fwd(
"+proj=ortel +R=1",
20.0,
30.0,
0.311919918291,
std::f64::consts::FRAC_PI_6,
1e-6,
);
check_fwd(
"+proj=ortel +R=1",
-120.0,
-40.0,
-1.930728204156,
-0.698131700798,
1e-6,
);
}
#[test]
fn nicol_forward() {
check_fwd(
"+proj=nicol +R=1",
20.0,
30.0,
0.310022779015,
0.536734059396,
1e-6,
);
check_fwd(
"+proj=nicol +R=1",
-120.0,
-40.0,
-1.535924384770,
-0.876536316796,
1e-6,
);
}
#[test]
fn larr_forward() {
check_fwd(
"+proj=larr +R=1",
20.0,
30.0,
0.336954113463,
0.542987990209,
1e-6,
);
check_fwd(
"+proj=larr +R=1",
-120.0,
-40.0,
-1.963746368302,
-0.790616231112,
1e-6,
);
}
#[test]
fn lask_forward() {
check_fwd(
"+proj=lask +R=1",
20.0,
30.0,
0.327520128501,
0.542640626452,
1e-6,
);
check_fwd(
"+proj=lask +R=1",
-120.0,
-40.0,
-1.830244626164,
-0.932593529443,
1e-6,
);
}
#[test]
fn august_forward() {
check_fwd(
"+proj=august +R=1",
20.0,
30.0,
0.337740025853,
0.550566293123,
1e-6,
);
check_fwd(
"+proj=august +R=1",
-120.0,
-40.0,
-2.287820872740,
-1.273715756799,
1e-6,
);
}
#[test]
fn gins8_forward() {
check_fwd(
"+proj=gins8 +R=1",
20.0,
30.0,
0.290162539370,
0.535561073700,
1e-6,
);
check_fwd(
"+proj=gins8 +R=1",
-120.0,
-40.0,
-1.642566087164,
-0.726486777780,
1e-6,
);
}