1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
use std::collections::VecDeque;
use std::time::Duration;
const HISTORY_LIMIT: Duration = Duration::from_millis(150);
const DECELERATION_TOUCHPAD: f64 = 0.997;
#[derive(Debug)]
pub struct SwipeTracker {
history: VecDeque<Event>,
pos: f64,
}
#[derive(Debug, Clone, Copy)]
struct Event {
delta: f64,
timestamp: Duration,
}
impl SwipeTracker {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
history: VecDeque::new(),
pos: 0.,
}
}
/// Pushes a new reading into the tracker.
pub fn push(&mut self, delta: f64, timestamp: Duration) {
// For the events that we care about, timestamps should always increase
// monotonically.
if let Some(last) = self.history.back() {
if timestamp < last.timestamp {
trace!(
"ignoring event with timestamp {timestamp:?} earlier than last {:?}",
last.timestamp
);
return;
}
}
self.history.push_back(Event { delta, timestamp });
self.pos += delta;
self.trim_history();
}
/// Returns the current gesture position.
pub fn pos(&self) -> f64 {
self.pos
}
/// Computes the current gesture velocity.
pub fn velocity(&self) -> f64 {
let (Some(first), Some(last)) = (self.history.front(), self.history.back()) else {
return 0.;
};
let total_time = (last.timestamp - first.timestamp).as_secs_f64();
if total_time == 0. {
return 0.;
}
let total_delta = self.history.iter().map(|event| event.delta).sum::<f64>();
total_delta / total_time
}
/// Computes the gesture end position after decelerating to a halt.
pub fn projected_end_pos(&self) -> f64 {
let vel = self.velocity();
self.pos - vel / (1000. * DECELERATION_TOUCHPAD.ln())
}
fn trim_history(&mut self) {
let Some(&Event { timestamp, .. }) = self.history.back() else {
return;
};
while let Some(first) = self.history.front() {
if timestamp <= first.timestamp + HISTORY_LIMIT {
break;
}
let _ = self.history.pop_front();
}
}
}
|