use geodesy::authoring::*;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Debug, Default)]
pub struct Maximal {
constructors: BTreeMap<String, OpConstructor>,
resources: BTreeMap<String, String>,
operators: BTreeMap<OpHandle, Op>,
}
const BAD_ID_MESSAGE: Error = Error::General("Maximal: Unknown operator id");
impl Context for Maximal {
fn new() -> Maximal {
Maximal::default()
}
fn op(&mut self, definition: &str) -> Result<OpHandle, Error> {
let op = Op::new(definition, self)?;
let id = OpHandle::new();
self.operators.insert(id, op);
assert!(self.operators.contains_key(&id));
Ok(id)
}
fn apply(
&self,
op: OpHandle,
direction: Direction,
operands: &mut dyn CoordinateSet,
) -> Result<usize, Error> {
let op = self.operators.get(&op).ok_or(BAD_ID_MESSAGE)?;
Ok(op.apply(self, operands, direction))
}
fn steps(&self, op: OpHandle) -> Result<Vec<String>, Error> {
let op = self.operators.get(&op).ok_or(BAD_ID_MESSAGE)?;
Ok(op.descriptor.instantiated_as.split_into_steps())
}
fn params(&self, op: OpHandle, index: usize) -> Result<ParsedParameters, Error> {
let op = self.operators.get(&op).ok_or(BAD_ID_MESSAGE)?;
if op.is_pipeline() {
let steps = op.steps.as_ref().unwrap();
if index >= steps.len() {
return Err(Error::General("Maximal: Bad step index"));
}
Ok(steps[index].params.clone())
} else {
if index > 0 {
return Err(Error::General("Maximal: Bad step index"));
}
Ok(op.params.clone())
}
}
fn globals(&self) -> BTreeMap<String, String> {
BTreeMap::from([("ellps".to_string(), "GRS80".to_string())])
}
fn register_op(&mut self, name: &str, constructor: OpConstructor) {
self.constructors.insert(String::from(name), constructor);
}
fn get_op(&self, name: &str) -> Result<OpConstructor, Error> {
if let Some(result) = self.constructors.get(name) {
return Ok(OpConstructor(result.0));
}
Err(Error::NotFound(
name.to_string(),
": User defined constructor".to_string(),
))
}
fn register_resource(&mut self, name: &str, definition: &str) {
self.resources
.insert(String::from(name), String::from(definition));
}
fn get_resource(&self, name: &str) -> Result<String, Error> {
if let Some(result) = self.resources.get(name) {
return Ok(result.to_string());
}
Err(Error::NotFound(
name.to_string(),
": User defined resource".to_string(),
))
}
fn get_blob(&self, name: &str) -> Result<Vec<u8>, Error> {
let n = PathBuf::from(name);
let ext = n
.extension()
.unwrap_or_default()
.to_str()
.unwrap_or_default();
let path: PathBuf = [".", "geodesy", ext, name].iter().collect();
Ok(std::fs::read(path)?)
}
fn get_grid(&self, name: &str) -> Result<Arc<BaseGrid>, Error> {
let buf = self.get_blob(name)?;
let grid = geodesy::grd::gravsoft::gravsoft(name, &buf)?;
Ok(Arc::new(grid))
}
}
#[cfg(test)]
mod tests {
use super::Maximal;
use geodesy::authoring::*;
#[test]
fn token() -> Result<(), Error> {
assert_eq!("foo bar $ baz = bonk".normalize(), "foo bar $baz=bonk");
assert_eq!(
"foo | bar baz = bonk, bonk , bonk".normalize(),
"foo|bar baz=bonk,bonk,bonk"
);
assert_eq!(
"foo | bar baz = bonk, bonk , bonk".split_into_steps()[0],
"foo"
);
assert_eq!("foo bar baz=bonk".split_into_parameters()["_name"], "foo");
assert_eq!("foo bar baz=bonk".split_into_parameters()["bar"], "true");
assert_eq!("foo bar baz=bonk".split_into_parameters()["baz"], "bonk");
assert!("foo | bar".is_pipeline());
assert!("foo:bar".is_resource_name());
assert_eq!("foo bar baz=bonk".operator_name(), "foo");
assert_eq!("foo bar baz= $bonk".operator_name(), "foo");
Ok(())
}
#[test]
fn maximal() -> Result<(), Error> {
let mut ctx = Maximal::default();
let op = ctx.op("gridshift grids=test.datum")?;
let cph = Coor4D::geo(55., 12., 0., 0.);
let mut data = [cph];
ctx.apply(op, Fwd, &mut data)?;
let res = data[0].to_geo();
assert!((res[0] - 55.015278).abs() < 1e-6);
assert!((res[1] - 12.003333).abs() < 1e-6);
ctx.apply(op, Inv, &mut data)?;
assert!((data[0][0] - cph[0]).abs() < 1e-10);
assert!((data[0][1] - cph[1]).abs() < 1e-10);
let cph = Coor4D::geo(55., 12., 0., 0.);
if let Ok(pj) = ctx.op("proj proj=utm zone=32") {
let rg = ctx.op("utm zone=32")?;
let mut data_rg = [cph];
let mut data_pj = [cph];
ctx.apply(rg, Fwd, &mut data_rg)?;
ctx.apply(pj, Fwd, &mut data_pj)?;
assert!((data_rg[0].hypot2(&data_pj[0]) < 1e-4));
}
Ok(())
}
}