use crate::authoring::*;
fn fwd(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
let mut successes = 0_usize;
let n = operands.len();
let sliced = 0..n;
let ellps = op.params.ellps(0);
if op.params.boolean("geocentric") {
for i in sliced {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geographic_to_geocentric(coord[1]);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("reduced") || op.params.boolean("parametric") {
for i in sliced {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geographic_to_reduced(coord[1]);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("conformal") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in sliced {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geographic_to_conformal(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("rectifying") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in sliced {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geographic_to_rectifying(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("authalic") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in sliced {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geographic_to_authalic(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
}
successes
}
fn inv(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
let mut successes = 0_usize;
let n = operands.len();
let ellps = op.params.ellps(0);
if op.params.boolean("geocentric") {
for i in 0..n {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_geocentric_to_geographic(coord[1]);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("reduced") || op.params.boolean("parametric") {
for i in 0..n {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_reduced_to_geographic(coord[1]);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("conformal") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in 0..n {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_conformal_to_geographic(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("rectifying") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in 0..n {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_rectifying_to_geographic(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
} else if op.params.boolean("authalic") {
let Some(coefficients) = op.params.fourier_coefficients.get("coefficients") else {
return 0;
};
for i in 0..n {
let mut coord = operands.get_coord(i);
coord[1] = ellps.latitude_authalic_to_geographic(coord[1], coefficients);
operands.set_coord(i, &coord);
successes += 1;
}
}
successes
}
#[rustfmt::skip]
pub const GAMUT: [OpParameter; 8] = [
OpParameter::Flag { key: "inv" },
OpParameter::Flag { key: "geocentric" },
OpParameter::Flag { key: "reduced" },
OpParameter::Flag { key: "parametric" },
OpParameter::Flag { key: "conformal" },
OpParameter::Flag { key: "authalic" },
OpParameter::Flag { key: "rectifying" },
OpParameter::Text { key: "ellps", default: Some("GRS80") }
];
pub fn new(parameters: &RawParameters, _ctx: &dyn Context) -> Result<Op, Error> {
let mut op = Op::basic(parameters, InnerOp(fwd), Some(InnerOp(inv)), &GAMUT)?;
let ellps = op.params.ellps(0);
let mut number_of_flags = 0_usize;
if op.params.boolean("geocentric") {
number_of_flags += 1;
}
if op.params.boolean("reduced") || op.params.boolean("parametric") {
number_of_flags += 1;
}
if op.params.boolean("conformal") {
let coefficients = ellps.coefficients_for_conformal_latitude_computations();
op.params
.fourier_coefficients
.insert("coefficients", coefficients);
number_of_flags += 1;
}
if op.params.boolean("authalic") {
let coefficients = ellps.coefficients_for_authalic_latitude_computations();
op.params
.fourier_coefficients
.insert("coefficients", coefficients);
number_of_flags += 1;
}
if op.params.boolean("rectifying") {
let coefficients = ellps.coefficients_for_rectifying_latitude_computations();
op.params
.fourier_coefficients
.insert("coefficients", coefficients);
number_of_flags += 1;
}
if number_of_flags != 1 {
return Err(Error::MissingParam("latitude: must specify exactly one of flags authalic/conformal/geocentric/rectifying/reduced/parametric".to_string()));
}
Ok(op)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn latitude() -> Result<(), Error> {
let mut ctx = Minimal::default();
let op = ctx.op("latitude geocentric ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.818_973_308_324_5).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
let op = ctx.op("latitude reduced ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.909_538_187_092_245).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
let op = ctx.op("latitude parametric ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.909_538_187_092_245).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
let op = ctx.op("latitude conformal ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.819_109_023_689_02).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
let op = ctx.op("latitude rectifying ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.772_351_809_646_84).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
let op = ctx.op("latitude authalic ellps=GRS80")?;
let mut operands = [Coor4D::geo(55., 12., 0., 0.)];
ctx.apply(op, Fwd, &mut operands)?;
assert!((operands[0][1].to_degrees() - 54.879_361_594_517_796).abs() < 1e-12);
ctx.apply(op, Inv, &mut operands)?;
assert!((operands[0][1].to_degrees() - 55.).abs() < 1e-12);
Ok(())
}
}