cranpose_animation/
decay_spec.rs1pub const IOS_DECELERATION_RATE_NORMAL: f32 = 0.998;
17
18pub const IOS_DECELERATION_RATE_FAST: f32 = 0.99;
21
22pub trait FloatDecayAnimationSpec {
27 fn abs_velocity_threshold(&self) -> f32;
29
30 fn get_value_from_nanos(
32 &self,
33 play_time_nanos: i64,
34 initial_value: f32,
35 initial_velocity: f32,
36 ) -> f32;
37
38 fn get_velocity_from_nanos(
40 &self,
41 play_time_nanos: i64,
42 initial_value: f32,
43 initial_velocity: f32,
44 ) -> f32;
45
46 fn get_duration_nanos(&self, initial_value: f32, initial_velocity: f32) -> i64;
48
49 fn get_target_value(&self, initial_value: f32, initial_velocity: f32) -> f32;
51}
52
53const REST_VELOCITY_PTS_PER_SEC: f64 = 0.1;
54
55#[derive(Debug, Clone, Copy)]
63pub struct ExponentialDecaySpec {
64 rate: f32,
65}
66
67impl ExponentialDecaySpec {
68 pub fn new(rate: f32) -> Self {
71 Self { rate }
72 }
73
74 fn ln_rate(&self) -> f64 {
75 (self.rate as f64).ln()
76 }
77}
78
79impl Default for ExponentialDecaySpec {
80 fn default() -> Self {
81 Self::new(IOS_DECELERATION_RATE_NORMAL)
82 }
83}
84
85impl FloatDecayAnimationSpec for ExponentialDecaySpec {
86 fn abs_velocity_threshold(&self) -> f32 {
87 REST_VELOCITY_PTS_PER_SEC as f32
88 }
89
90 fn get_value_from_nanos(
91 &self,
92 play_time_nanos: i64,
93 initial_value: f32,
94 initial_velocity: f32,
95 ) -> f32 {
96 let t_ms = play_time_nanos as f64 / 1_000_000.0;
97 let v0_per_ms = initial_velocity as f64 / 1000.0;
98 let ln_rate = self.ln_rate();
99 let delta = v0_per_ms * ((self.rate as f64).powf(t_ms) - 1.0) / ln_rate;
100 initial_value + delta as f32
101 }
102
103 fn get_velocity_from_nanos(
104 &self,
105 play_time_nanos: i64,
106 _initial_value: f32,
107 initial_velocity: f32,
108 ) -> f32 {
109 let t_ms = play_time_nanos as f64 / 1_000_000.0;
110 (initial_velocity as f64 * (self.rate as f64).powf(t_ms)) as f32
111 }
112
113 fn get_duration_nanos(&self, _initial_value: f32, initial_velocity: f32) -> i64 {
114 let v0 = initial_velocity.abs() as f64;
115 if v0 <= REST_VELOCITY_PTS_PER_SEC {
116 return 0;
117 }
118 let t_ms = (REST_VELOCITY_PTS_PER_SEC / v0).ln() / self.ln_rate();
119 (t_ms * 1_000_000.0) as i64
120 }
121
122 fn get_target_value(&self, initial_value: f32, initial_velocity: f32) -> f32 {
123 let v0_per_ms = initial_velocity as f64 / 1000.0;
124 initial_value - (v0_per_ms / self.ln_rate()) as f32
125 }
126}
127
128#[cfg(test)]
129#[path = "tests/decay_spec_tests.rs"]
130mod tests;