pub const IOS_DECELERATION_RATE_NORMAL: f32 = 0.998;
pub const IOS_DECELERATION_RATE_FAST: f32 = 0.99;
pub trait FloatDecayAnimationSpec {
fn abs_velocity_threshold(&self) -> f32;
fn get_value_from_nanos(
&self,
play_time_nanos: i64,
initial_value: f32,
initial_velocity: f32,
) -> f32;
fn get_velocity_from_nanos(
&self,
play_time_nanos: i64,
initial_value: f32,
initial_velocity: f32,
) -> f32;
fn get_duration_nanos(&self, initial_value: f32, initial_velocity: f32) -> i64;
fn get_target_value(&self, initial_value: f32, initial_velocity: f32) -> f32;
}
const REST_VELOCITY_PTS_PER_SEC: f64 = 0.1;
#[derive(Debug, Clone, Copy)]
pub struct ExponentialDecaySpec {
rate: f32,
}
impl ExponentialDecaySpec {
pub fn new(rate: f32) -> Self {
Self { rate }
}
fn ln_rate(&self) -> f64 {
(self.rate as f64).ln()
}
}
impl Default for ExponentialDecaySpec {
fn default() -> Self {
Self::new(IOS_DECELERATION_RATE_NORMAL)
}
}
impl FloatDecayAnimationSpec for ExponentialDecaySpec {
fn abs_velocity_threshold(&self) -> f32 {
REST_VELOCITY_PTS_PER_SEC as f32
}
fn get_value_from_nanos(
&self,
play_time_nanos: i64,
initial_value: f32,
initial_velocity: f32,
) -> f32 {
let t_ms = play_time_nanos as f64 / 1_000_000.0;
let v0_per_ms = initial_velocity as f64 / 1000.0;
let ln_rate = self.ln_rate();
let delta = v0_per_ms * ((self.rate as f64).powf(t_ms) - 1.0) / ln_rate;
initial_value + delta as f32
}
fn get_velocity_from_nanos(
&self,
play_time_nanos: i64,
_initial_value: f32,
initial_velocity: f32,
) -> f32 {
let t_ms = play_time_nanos as f64 / 1_000_000.0;
(initial_velocity as f64 * (self.rate as f64).powf(t_ms)) as f32
}
fn get_duration_nanos(&self, _initial_value: f32, initial_velocity: f32) -> i64 {
let v0 = initial_velocity.abs() as f64;
if v0 <= REST_VELOCITY_PTS_PER_SEC {
return 0;
}
let t_ms = (REST_VELOCITY_PTS_PER_SEC / v0).ln() / self.ln_rate();
(t_ms * 1_000_000.0) as i64
}
fn get_target_value(&self, initial_value: f32, initial_velocity: f32) -> f32 {
let v0_per_ms = initial_velocity as f64 / 1000.0;
initial_value - (v0_per_ms / self.ln_rate()) as f32
}
}
#[cfg(test)]
#[path = "tests/decay_spec_tests.rs"]
mod tests;