use super::{FloatAdder, atan2, cos, mul_add, sin};
use core::f64::consts::PI;
pub trait Coord2d {
fn xy(self) -> (f64, f64);
}
pub fn linear_ring_area<CoordType>(ring: &[CoordType]) -> f64
where
CoordType: Coord2d + Copy,
{
let mut adder = FloatAdder::default();
for (a, b) in ring.iter().zip(ring.iter().cycle().skip(1)) {
adder += cagnoli(a.xy(), b.xy());
}
if f64::from(adder) < 0. {
adder += 4. * PI;
}
adder.into()
}
fn cagnoli((a_x, a_y): (f64, f64), (b_x, b_y): (f64, f64)) -> f64 {
let a_lat = mul_add(a_y, 0.5, PI * 0.25);
let b_lat = mul_add(b_y, 0.5, PI * 0.25);
let sin_a = sin(a_lat) * sin(b_lat);
let cos_a = cos(a_lat) * cos(b_lat);
let delta = b_x - a_x;
let sin_d = sin(delta);
let cos_d = cos(delta);
-2. * atan2(sin_a * sin_d, sin_a * cos_d + cos_a)
}
#[cfg(test)]
#[path = "./area_tests.rs"]
mod tests;