use crate::context::Context;
use crate::params::{ParamList, ParamView};
use crate::pj::Pj;
use oxiproj_core::{Ellipsoid, ProjResult};
pub fn build_single_op(
name: &str,
params: &ParamList,
ellipsoid: Ellipsoid,
context: &Context,
) -> ProjResult<Pj> {
let lam0 = params.get_dms("lon_0").unwrap_or(0.0);
let phi0 = params.get_dms("lat_0").unwrap_or(0.0);
let x0 = params.get_f64("x_0").unwrap_or(0.0);
let y0 = params.get_f64("y_0").unwrap_or(0.0);
let z0 = params.get_f64("z_0").unwrap_or(0.0);
let k0 = params
.get_f64("k_0")
.or_else(|| params.get_f64("k"))
.unwrap_or(1.0);
let (to_meter, fr_meter) = match params.get_f64("to_meter") {
Some(v) if v != 0.0 => (v, 1.0 / v),
_ => match params.get_str("units") {
Some(u) => match oxiproj_core::find_linear_unit(u) {
Some(ud) => (ud.factor, 1.0 / ud.factor),
None => (1.0, 1.0),
},
None => (1.0, 1.0),
},
};
let (vto_meter, vfr_meter) = match params.get_f64("vto_meter") {
Some(v) if v != 0.0 => (v, 1.0 / v),
_ => match params.get_str("vunits") {
Some(u) => match oxiproj_core::find_linear_unit(u) {
Some(ud) => (ud.factor, 1.0 / ud.factor),
None => (1.0, 1.0),
},
None => (1.0, 1.0),
},
};
let over = params.get_bool("over");
let geoc = params.get_bool("geoc");
let from_greenwich = match params.get_str("pm") {
Some(pm) => oxiproj_core::prime_meridian_offset(pm)
.or_else(|_| oxiproj_core::dmstor(pm))
.unwrap_or(0.0),
None => 0.0,
};
let view = ParamView(params);
let pp = oxiproj_projections::ProjParams {
ellipsoid: &ellipsoid,
phi0,
k0,
params: &view,
};
match oxiproj_projections::build(name, &pp) {
Ok(build) => {
let lam0 = build.lam0_override.unwrap_or(lam0);
let k0 = build.k0_override.unwrap_or(k0);
let x0 = build.x0_override.unwrap_or(x0);
let y0 = build.y0_override.unwrap_or(y0);
let phi0 = build.phi0_override.unwrap_or(phi0);
Ok(Pj {
operation: build.operation,
ellipsoid,
lam0,
phi0,
x0,
y0,
z0,
k0,
to_meter,
fr_meter,
vto_meter,
vfr_meter,
from_greenwich,
over,
geoc,
is_latlong: build.is_latlong,
left: build.left,
right: build.right,
inverted: false,
bypass_prepare_finalize: false,
})
}
Err(oxiproj_core::ProjError::InvalidOp) => {
let tp = oxiproj_transformations::TransParams {
ellipsoid: &ellipsoid,
params: &view,
registry: Some(context as &dyn oxiproj_transformations::GridRegistry),
};
let tb = oxiproj_transformations::build(name, &tp)?;
Ok(Pj {
operation: tb.operation,
ellipsoid,
lam0: 0.0,
phi0: 0.0,
x0: 0.0,
y0: 0.0,
z0: 0.0,
k0: 1.0,
to_meter: 1.0,
fr_meter: 1.0,
vto_meter: 1.0,
vfr_meter: 1.0,
from_greenwich: 0.0,
over: false,
geoc: false,
is_latlong: false,
left: tb.left,
right: tb.right,
inverted: false,
bypass_prepare_finalize: true,
})
}
Err(e) => Err(e),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::params::parse;
use oxiproj_core::{Coord, DEG_TO_RAD};
#[test]
fn merc_known_value() {
let ell = Ellipsoid::named("WGS84").unwrap();
let pj = build_single_op(
"merc",
&parse("+proj=merc +ellps=WGS84"),
ell,
&Context::new(),
)
.unwrap();
let out = pj
.forward(Coord::new(12.0 * DEG_TO_RAD, 55.0 * DEG_TO_RAD, 0.0, 0.0))
.unwrap();
let o = out.v();
assert!((o[0] - 1335833.8895192828).abs() < 1e-6, "x got {}", o[0]);
assert!(
(o[1] - 7_326_837.715_045_549).abs() < 1e-6,
"y got {}",
o[1]
);
}
#[test]
fn utm_central_meridian_origin() {
let ell = Ellipsoid::named("WGS84").unwrap();
let pj = build_single_op(
"utm",
&parse("+proj=utm +zone=32 +ellps=WGS84"),
ell,
&Context::new(),
)
.unwrap();
let out = pj
.forward(Coord::new(9.0 * DEG_TO_RAD, 0.0, 0.0, 0.0))
.unwrap();
let o = out.v();
assert!((o[0] - 500000.0).abs() < 1e-6, "x got {}", o[0]);
assert!((o[1] - 0.0).abs() < 1e-6, "y got {}", o[1]);
}
}