use crate::{math::interpolate, noise_fns::NoiseFn};
pub struct Select<'a, T> {
pub source1: &'a dyn NoiseFn<T>,
pub source2: &'a dyn NoiseFn<T>,
pub control: &'a dyn NoiseFn<T>,
pub bounds: (f64, f64),
pub falloff: f64,
}
impl<'a, T> Select<'a, T> {
pub fn new(
source1: &'a dyn NoiseFn<T>,
source2: &'a dyn NoiseFn<T>,
control: &'a dyn NoiseFn<T>,
) -> Self {
Select {
source1,
source2,
control,
bounds: (0.0, 1.0),
falloff: 0.0,
}
}
pub fn set_bounds(self, lower_bound: f64, upper_bound: f64) -> Self {
Select {
bounds: (lower_bound, upper_bound),
..self
}
}
pub fn set_falloff(self, falloff: f64) -> Self {
Select { falloff, ..self }
}
}
impl<'a, T> NoiseFn<T> for Select<'a, T>
where
T: Copy,
{
fn get(&self, point: T) -> f64 {
let control_value = self.control.get(point);
let (lower, upper) = self.bounds;
if self.falloff > 0.0 {
match () {
_ if control_value < (lower - self.falloff) => self.source1.get(point),
_ if control_value < (lower + self.falloff) => {
let lower_curve = lower - self.falloff;
let upper_curve = lower + self.falloff;
let alpha = interpolate::s_curve3(
(control_value - lower_curve) / (upper_curve - lower_curve),
);
interpolate::linear(self.source1.get(point), self.source2.get(point), alpha)
}
_ if control_value < (upper - self.falloff) => self.source2.get(point),
_ if control_value < (upper + self.falloff) => {
let lower_curve = upper - self.falloff;
let upper_curve = upper + self.falloff;
let alpha = interpolate::s_curve3(
(control_value - lower_curve) / (upper_curve - lower_curve),
);
interpolate::linear(self.source2.get(point), self.source1.get(point), alpha)
}
_ => self.source1.get(point),
}
} else if control_value < lower || control_value > upper {
self.source1.get(point)
} else {
self.source2.get(point)
}
}
}