use crate::spherical::{LatLon, LonLatBbox, haversine, signed_lon_delta, wrap_lon_deg};
use crate::units::{Path, PathXY};
fn lerp(a: f64, b: f64, t: f64) -> f64 {
a + (b - a) * t
}
#[derive(Copy, Clone, Debug)]
pub struct RouteBounds {
pub origin: LatLon,
pub destination: LatLon,
pub bbox: LonLatBbox,
pub step_distance_max: f64,
}
pub const DEFAULT_STEP_DISTANCE_FRACTION: f64 = 0.01;
impl RouteBounds {
pub fn new(
origin: impl Into<LatLon>,
destination: impl Into<LatLon>,
bbox: LonLatBbox,
) -> Self {
Self::new_with_step_fraction(origin, destination, bbox, DEFAULT_STEP_DISTANCE_FRACTION)
}
pub fn new_with_step_fraction(
origin: impl Into<LatLon>,
destination: impl Into<LatLon>,
bbox: LonLatBbox,
fraction: f64,
) -> Self {
let diagonal_m = haversine(
LatLon::new(bbox.lon_min, bbox.lat_min),
LatLon::new(bbox.lon_max, bbox.lat_max),
);
Self {
origin: origin.into(),
destination: destination.into(),
bbox,
step_distance_max: diagonal_m * fraction,
}
}
pub fn constrain_endpoints_xy<const N: usize>(&self, path: &mut PathXY<N>) {
path.set_lat_lon(0, self.origin);
path.set_lat_lon(N - 1, self.destination);
}
pub fn constrain_endpoints_xyt<const N: usize>(&self, path: &mut Path<N>) {
self.constrain_endpoints_xy(&mut path.xy);
path.t[0] = 0.0;
}
pub fn clamp(&self, p: LatLon) -> LatLon {
self.bbox.clamp(p)
}
pub fn constrain_xy<const N: usize>(&self, pos: &Path<N>) -> Path<N> {
let mut clamped: Path<N> = Path::default();
self.constrain_endpoints_xyt(&mut clamped);
for i in 1..N - 1 {
clamped.xy.set_lat_lon(i, self.clamp(pos.xy.lat_lon(i)));
}
clamped
}
pub fn lerp_between_endpoints(&self, t: f64) -> LatLon {
let dlon = signed_lon_delta(self.origin.lon, self.destination.lon);
let lon = wrap_lon_deg(self.origin.lon + t * dlon);
let lat = lerp(self.origin.lat, self.destination.lat, t);
LatLon::new(lon, lat)
}
}