// examples/02-user_defined_macros.rs

// See also 00-transformations.rs
// Run with:
// cargo run --example 02-user_defined_macros
use geodesy::prelude::*;

fn main() -> anyhow::Result<()> {
    let mut ctx = Minimal::default();

    // Same test coordinates as in example 00.
    let cph = Coor3D::gis(12., 55., 0.); // Copenhagen
    let osl = Coor3D::gis(10., 60., 0.); // Oslo
    let sth = Coor3D::geo(59., 18., 0.); // Stockholm
    let hel = Coor3D::geo(60., 25., 0.); // Helsinki

    let mut data = [osl, cph, sth, hel];

    // In example 00, we instantiated a pipeline comprising a Helmert
    // transformation sandwiched between conversions between geodetic/
    // cartesian coordinates.
    // Since this cartesian|helmert|geodetic triplet is quite useful in
    // its own right, then why not create a macro, making it immediately
    // available under the name `geohelmert`?
    let geohelmert_macro_text = "cart ellps=$left | helmert | cart inv ellps=$right";
    // Note the '$'-sigils. Within a macro, the sigil looks up and
    // captures values set in the calling environment, as will become
    // clear in a moment...

    // First we need to register our macro in the resource provider ("context")
    ctx.register_resource("geo:helmert", geohelmert_macro_text);

    // Now let's see whether it works - instantiate the macro, using the same
    // parameters as used in example 00. The ':' in the operator name invokes
    // the macro expansion machinery.
    let ed50_etrs89 = ctx.op("geo:helmert left=intl right=GRS80 x=-87 y=-96 z=-120")?;
    // ... and do the same transformation as in example 00
    ctx.apply(ed50_etrs89, Fwd, &mut data)?;

    println!("etrs89:");
    for coord in data {
        println!("    {:?}", coord.to_geo());
    }

    ctx.apply(ed50_etrs89, Inv, &mut data)?;

    // data.to_geo() transforms all elements in data from the internal GIS
    // format (lon/lat in radians) to lat/lon in degrees.
    println!("Back to ed50:");
    for coord in data {
        println!("    {:?}", coord.to_geo());
    }

    Ok(())
}
