use crate::route_bounds::RouteBounds;
use crate::spherical::{LatLon, Segment, TangentMetres, Wind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SeaPathBias {
None,
North,
South,
}
pub trait WindSource: Sync {
fn sample_wind(&self, location: LatLon, t: f64) -> Wind;
}
pub struct WindSourceDummy;
impl WindSource for WindSourceDummy {
fn sample_wind(&self, _location: LatLon, _t: f64) -> Wind {
Wind::zero()
}
}
pub trait Sailboat: Sync {
fn get_fuel_consumed(&self, mcr_01: f64, delta_time: f64) -> f64;
fn get_travel_time<WS: WindSource>(
&self,
wind_source: &WS,
segment: Segment,
mcr_01: f64,
) -> f64;
fn get_travel_times_for_mcrs<WS: WindSource>(
&self,
wind_source: &WS,
segment: Segment,
mcr_01_values: &[f64],
out: &mut [f64],
) {
debug_assert_eq!(
mcr_01_values.len(),
out.len(),
"out buffer must match input mcr_01 length",
);
for (i, &mcr) in mcr_01_values.iter().enumerate() {
out[i] = self.get_travel_time(wind_source, segment, mcr);
}
}
}
pub trait LandmassSource: Sync {
fn signed_distance_m(&self, location: LatLon) -> f64;
fn gradient(&self, _location: LatLon) -> TangentMetres {
TangentMetres::zero()
}
fn is_land(&self, location: LatLon) -> bool {
self.signed_distance_m(location) < 0.0
}
fn find_sea_path(
&self,
_origin: LatLon,
_destination: LatLon,
_bounds: &RouteBounds,
_bias: SeaPathBias,
) -> Option<Vec<LatLon>> {
None
}
}
pub struct LandmassSourceDummy;
impl LandmassSource for LandmassSourceDummy {
fn signed_distance_m(&self, _location: LatLon) -> f64 {
f64::INFINITY
}
}
pub trait SailboatFitData: Sync {
type Ship: Sailboat;
type Wind: WindSource;
type Land: LandmassSource;
fn ship(&self) -> &Self::Ship;
fn wind_source(&self) -> &Self::Wind;
fn landmass(&self) -> &Self::Land;
fn step_distance_max(&self) -> f64;
fn departure_time(&self) -> f64;
fn time_weight(&self) -> f64;
fn fuel_weight(&self) -> f64;
fn land_weight(&self) -> f64;
}