use num::{Float, NumCast};
use super::{Approximation, Curve, Threshold};
use crate::threshold::{And, DisplacementThreshold, VelocityThreshold};
#[derive(Copy, Clone)]
pub struct Sampler<'a, C, T>
where
C: Curve + ?Sized,
T: Threshold,
{
curve: &'a C,
sample_rate: f32,
threshold: T,
time: f32,
exhausted: bool,
}
impl<'a, C, T> Sampler<'a, C, T>
where
C: Curve + ?Sized,
T: Threshold<Value = C::Value>,
{
pub fn with_threshold(curve: &'a C, sample_rate: f32, threshold: T) -> Sampler<'a, C, T> {
Sampler {
curve,
sample_rate,
threshold,
time: 0.0,
exhausted: false,
}
}
pub fn keyed(self) -> KeyedIter<'a, C, T> {
KeyedIter(self)
}
}
impl<'a, C, T> Sampler<'a, C, And<VelocityThreshold<T>, DisplacementThreshold<T>>>
where
C: Curve<Value = T> + ?Sized,
T: Float,
{
pub fn new(
curve: &'a C,
sample_rate: f32,
) -> Sampler<'a, C, And<VelocityThreshold<T>, DisplacementThreshold<T>>> {
Sampler::with_thresholds(
curve,
sample_rate,
<T as NumCast>::from(0.001).unwrap(),
<T as NumCast>::from(0.001).unwrap(),
)
}
pub fn with_thresholds(
curve: &'a C,
sample_rate: f32,
rest_velocity_threshold: T,
rest_displacement_threshold: T,
) -> Sampler<'a, C, And<VelocityThreshold<T>, DisplacementThreshold<T>>> {
Sampler::with_threshold(
curve,
sample_rate,
And(
VelocityThreshold(rest_velocity_threshold),
DisplacementThreshold {
target: curve.target(),
sensitivity: rest_displacement_threshold,
},
),
)
}
}
impl<'a, C, T> Iterator for Sampler<'a, C, T>
where
C: Curve + ?Sized,
T: Threshold<Value = C::Value, Velocity = C::Velocity>,
{
type Item = Approximation<C::Value, C::Velocity>;
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
return None;
}
let mut approx = self.curve.approximate(self.time);
self.time = self.time + 1.0 / self.sample_rate;
if self.threshold.evaluate(&approx) {
self.exhausted = true;
approx.value = self.curve.target();
}
Some(approx)
}
}
pub struct KeyedIter<'a, C, T>(Sampler<'a, C, T>)
where
C: Curve + ?Sized,
T: Threshold<Value = C::Value>;
impl<'a, C, T> Iterator for KeyedIter<'a, C, T>
where
C: Curve + ?Sized,
T: Threshold<Value = C::Value, Velocity = C::Velocity>,
{
type Item = (f32, Approximation<C::Value, C::Velocity>);
fn next(&mut self) -> Option<Self::Item> {
let time = self.0.time;
Some((time, self.0.next()?))
}
}