use std::collections::VecDeque;
use std::borrow::Borrow;
type Timestamp = u64;
type Time = f64; type TimeDelta = f64;
type TimeDeltaMicros = u64;
type Velocity = f64;
type Position = f64;
use crate::CONFIG as sconfig;
#[derive(Clone, Copy, Debug, PartialEq)]
enum Phase {
Inactive,
Interpolating,
Released(Time), }
enum TrackPosition {
Top,
Bottom,
}
enum BounceState {
Bouncing(TrackPosition),
Normal,
}
#[derive(Clone, Copy, Debug, PartialOrd)]
struct Event {
time: Time, value: f64, }
impl std::fmt::Display for Event {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}: {})", self.time, self.value)
}
}
impl std::cmp::Ord for Event {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let cmp_time = self.time.partial_cmp(&other.time).expect("NaN in time field of an event");
match cmp_time {
std::cmp::Ordering::Equal => self.value.partial_cmp(&other.value).expect("NaN in value field of an event"),
other => other
}
}
}
impl std::cmp::PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.time == other.time
}
}
impl std::cmp::Eq for Event {}
#[derive(Clone, Copy)]
struct Sample {
time: Time,
velocity: Velocity,
position: Position,
}
impl std::fmt::Display for Sample {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}: {}, {})", self.time, self.position, self.velocity)
}
}
pub struct Interpolator {
redistributable: bool,
events: VecDeque<Event>,
samples: VecDeque<Sample>,
pan_start_time: Time,
current_phase: Phase,
track_bound_upper: f64,
track_bound_lower: f64,
track_initial_pos: f64,
bouncing: BounceState,
min_tick_period: TimeDelta,
last_value: f64,
flips_same_value: u64,
source: crate::Source,
}
impl Interpolator {
pub fn set_source(&mut self, source: crate::Source) {
self.source = source;
}
pub fn print_events(&self) {
return;
println!("Current events are {{{}}}",
self.events.iter().fold(
String::new(), |s, evt| { s.to_owned() + &evt.to_string()[..] }));
}
pub fn new(redistributable: bool, track_bounds: (f64, f64), initial_position: f64) -> Interpolator {
Interpolator {
redistributable,
events: VecDeque::with_capacity(5),
samples: VecDeque::new(),
pan_start_time: 0.0,
min_tick_period: f64::INFINITY,
current_phase: Phase::Inactive,
track_bound_lower: track_bounds.0,
track_bound_upper: track_bounds.1,
track_initial_pos: initial_position,
flips_same_value: 0,
last_value: 0.0,
bouncing: BounceState::Normal,
source: crate::Source::Undefined,
}
}
pub fn sample(&mut self, time: Time) -> Position {
let config = sconfig.read().unwrap();
self.prevent_coast(time);
let last_sample = self.samples.back().map(|&evt| evt).unwrap_or(Sample { time, velocity: 0.0, position: 0.0 });
let iter = iter_range(last_sample.time + config.SHIFT_WINDOW_MS, time + config.SHIFT_WINDOW_MS, config.TIMESTEP);
let mut cur_position = last_sample.position;
let mut cur_velocity = last_sample.velocity;
for (start, end) in iter {
let stepped_velocity = self.step_velocity(start, end, cur_position, cur_velocity);
let velocity_per_step = (stepped_velocity + cur_velocity) / config.TIMESTEP;
let time_delta = end - start;
let integral = time_delta * velocity_per_step;
cur_position += integral;
cur_velocity = stepped_velocity;
}
self.samples.push_back(Sample { time, velocity: cur_velocity, position: cur_position });
self.cull();
self.check_idle(cur_position, cur_velocity);
cur_position
}
pub fn cull(&mut self) {
let config = sconfig.read().unwrap();
while self.samples.len() > config.SAMPLE_EXPIRY_COUNT {
self.samples.pop_front();
}
while self.events.len() > config.EVENT_EXPIRY_COUNT {
self.events.pop_front();
}
}
pub fn signal_fling(&mut self, time: Time) {
self.current_phase = Phase::Released(time);
}
pub fn signal_interrupt(&mut self, time: Time) {
println!("Interrupt at {}", time);
self.current_phase = Phase::Inactive;
self.flush(time);
self.min_tick_period = f64::INFINITY;
}
pub fn signal_pan(&mut self, time: Time, delta: f64) {
if time == 0.0 {
panic!("can't pass zero timestamps into signal_pan");
}
self.current_phase = Phase::Interpolating;
let (prev_val, prev_time) = self.events.back().map(|evt| (evt.value, evt.time)).unwrap_or((self.track_initial_pos, f64::NEG_INFINITY));
let current_val = prev_val + delta;
if time - prev_time <= 0.0 {
self.samples.retain(|s| s.time < prev_time);
self.events.pop_back();
} else {
self.min_tick_period = time - prev_time;
}
self.events.push_back(Event { value: current_val, time });
}
pub fn animating(&self) -> bool {
let r = match self.current_phase {
Phase::Inactive => false,
_ => true,
};
r
}
pub fn set_geometry(&mut self, min: f64, max: f64) {
self.track_bound_upper = max;
self.track_bound_lower = min;
}
}
impl Interpolator {
fn flush(&mut self, time: Time) {
}
fn check_idle(&mut self, position: Position, velocity: Velocity) {
let config = sconfig.read().unwrap();
match self.current_phase {
Phase::Released(_) => {
if position == self.last_value || velocity.abs() < config.MIN_VELOCITY_TO_IDLE {
self.flips_same_value += 1;
} else {
self.flips_same_value = 0;
}
self.last_value = position;
if self.flips_same_value > config.FLIPS_TO_IDLE {
eprintln!("Goes to idle");
println!("check_idle goes to Inactive");
self.current_phase = Phase::Inactive;
}
},
Phase::Interpolating => {
self.flips_same_value = 0;
},
Phase::Inactive => {}
}
}
fn prevent_coast(&mut self, time: Time) {
let config = sconfig.read().unwrap();
match self.current_phase {
Phase::Interpolating => match self.events.len() {
0 => {}
_ => {
let evt = self.events.back().expect("Events was empty despite len > 0");
let delta = (time - evt.time).abs();
if delta > self.min_tick_period * config.TICKS_TO_COAST || delta > config.MAX_MS_WITHOUT_ZERO_INJECTION {
println!("Clamps to prevent coast. Delta {} evt {} min_tick_period {}", delta, evt, self.min_tick_period);
self.signal_interrupt(time);
}
}
},
_ => {},
}
}
fn interpolate(&self, time: Time) -> Velocity {
let config = sconfig.read().unwrap();
let first_before = self
.events
.iter()
.filter(|evt| evt.time < time)
.max_by(|evt_a, evt_b| (evt_a.time as u64).cmp(&(evt_b.time as u64)));
let first_after = self
.events
.iter()
.filter(|evt| evt.time >= time)
.min_by(|evt_a, evt_b| (evt_a.time as u64).cmp(&(evt_b.time as u64)));
let second_before = match first_before {
None => None,
Some(first) => {
self
.events
.iter()
.filter(|evt| evt.time < first.time)
.max_by(|evt_a, evt_b| (evt_a.time as u64).cmp(&(evt_b.time as u64)))
}
};
let second_after = match first_after {
None => None,
Some(first) => {
self
.events
.iter()
.filter(|evt| evt.time < first.time)
.min_by(|evt_a, evt_b| (evt_a.time as u64).cmp(&(evt_b.time as u64)))
}
};
let events: Vec<&Event> = vec![&second_before, &first_before, &first_after]
.into_iter()
.filter_map(|&evt| evt) .collect();
let result = match events.len() {
0 => {
0.0
},
1 => {
let evt = events.first().expect("no elements in size 1 vec");
evt.value / config.MAX_MS_WITHOUT_ZERO_INJECTION
}
2 => Self::interpolate_linear(&events, time),
3 => Self::interpolate_linear_averaging(&events, time),
4 => Self::interpolate_hermite(&events, time),
_ => panic!("Programming error: events len greater than 4"),
};
if events.len() == 1 {
}
if result == 0.0 {
}
result
}
fn outside_bounds(&self, position: Position) -> bool {
let config = sconfig.read().unwrap();
position > self.track_bound_upper || position < self.track_bound_lower
}
fn short_circuit_single_event(&self) -> Position {
let config = sconfig.read().unwrap();
self.events.back().map(|evt| evt.value).unwrap_or(0.0)
}
fn fling_boost(&self, velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
velocity * config.FLING_BOOST_CONSTANT_FACTOR
}
fn handle_overscroll(&self, start: Time, end: Time, position: Position, velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
if self.outside_bounds(position) {
if self.source.overscrolls() {
let outside_by = if position > self.track_bound_upper {
if velocity < 0.0 {
return velocity;
}
position - self.track_bound_upper
} else {
if velocity > 0.0 {
return velocity;
}
self.track_bound_lower - position
};
let abs_vel = velocity.abs();
let timedelta = end - start;
let r_velocity = velocity * (1.0 / (outside_by * config.OVERSCROLL_ELASTICITY_COEFFICIENT));
if r_velocity.is_nan() {
panic!("handle_overscroll tried to return NaN");
}
r_velocity
} else {
if velocity < 0.0 && position < self.track_bound_upper {
0.0
} else if velocity > 0.0 && position > self.track_bound_lower {
0.0
} else {
velocity
}
}
} else {
velocity
}
}
fn accelerate(&self, velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
if self.source.accelerates() {
(velocity / config.ACCEL_DECEL_DESCRIMINANT).abs().powf(config.ACCELERATION_EXPONENT).copysign(velocity) * config.ACCEL_DECEL_DESCRIMINANT
} else {
velocity
}
}
fn pre_scale(&self, velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
velocity * config.PRE_ACCEL_SCALE_VELOCITY
}
fn post_scale(&self, velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
velocity * config.POST_ACCEL_SCALE_VELOCITY
}
fn decay(&self, start: Time, end: Time, _position: Position, old_velocity: Velocity) -> Velocity {
if old_velocity.is_nan() {
panic!("given NaN velocity");
}
if old_velocity == 0.0 {
return 0.0;
}
let timedelta = end - start;
let abs_vel = old_velocity.abs();
if timedelta < 0.0 {
panic!("Negative timedelta passed to decay");
}
let friction_factor = if old_velocity != 0.0 {
old_velocity.abs().powf(1.3) / old_velocity.abs()
} else {
0.0
};
let slope = -0.00009 * friction_factor;
let new_vel = abs_vel + slope * timedelta;
let floored = if new_vel < 0.0 {
0.0
} else {
new_vel.copysign(old_velocity)
};
if floored.abs() > old_velocity.abs() {
panic!("Somehow accelerated");
}
if floored.is_nan() {
panic!("tried to return NaN velocity. Given {}", old_velocity);
}
floored
}
fn bounce(&mut self, start: Time, end: Time, position: Position, old_velocity: Velocity) -> Velocity {
let config = sconfig.read().unwrap();
if self.outside_bounds(position) {
let trackposition = if position > self.track_bound_upper {
TrackPosition::Bottom
} else {
TrackPosition::Top
};
self.bouncing = BounceState::Bouncing(trackposition);
}
match &self.bouncing {
BounceState::Normal => old_velocity,
BounceState::Bouncing(trackposition) => {
if old_velocity.is_nan() {
panic!("Given NaN velocity");
}
let displacement = match trackposition {
TrackPosition::Top => position - self.track_bound_lower,
TrackPosition::Bottom => position - self.track_bound_upper,
};
let force = -displacement * config.OVERSCROLL_SPRING_CONSTANT;
let timedelta = end - start;
let acceleration = force / config.CONTENT_MASS_VALUE;
let velocity = old_velocity + acceleration * timedelta;
let velocity = velocity * config.BOUNCE_DAMP_FACTOR;
if velocity.is_nan() {
panic!("Velocity was NaN");
} else if velocity.is_infinite() {
panic!();
}
velocity
}
}
}
fn sample_velocity(&self, start: Time, end: Time) -> Velocity {
let p1 = self.interpolate(start);
let p2 = self.interpolate(end);
let timedelta = end - start;
let vel = (p2 - p1) * timedelta;
vel
}
fn step_velocity(&mut self, start: Time, end: Time, position: Position, old_velocity: Velocity) -> Velocity {
match self.current_phase {
Phase::Released(release_time) if release_time < start && release_time >= end => {
let r = self.fling_boost(old_velocity);
r
},
Phase::Released(release_time) if release_time < start => {
let b = self.bounce(
start,
end,
position,
old_velocity);
let r = self.decay(
start,
end,
position,
b);
r
},
Phase::Interpolating | Phase::Released(_) => {
self.bouncing = BounceState::Normal;
let r = self.post_scale(
self.handle_overscroll(
start,
end,
position,
self.accelerate(
self.pre_scale(
self.sample_velocity(start, end)))));
r
},
Phase::Inactive => 0.0
}
}
fn set_inactive(&mut self) {
println!("set_inactive sets Inactive");
self.current_phase = Phase::Inactive;
self.bouncing = BounceState::Normal;
self.samples.clear();
}
}
impl Interpolator {
fn sample_linear(first: &Event, second: &Event, sample: Time) -> f64 {
let slope = Self::slope_of(first, second);
slope * (sample - first.time) + first.value
}
fn slope_of(first: &Event, second: &Event) -> f64 {
if first.time == second.time {
0.0
} else {
(first.value - second.value) / ((first.time as i64) - (second.time as i64)) as f64
}
}
fn rounds_to_zero(val: f64) -> bool {
val.abs() < 0.5
}
fn interpolate_constant(events: &Vec<&Event>, at: Time) -> f64 {
let vel = events.first().expect("interpolate_constant given empty events vec").value;
vel
}
fn interpolate_linear(events: &Vec<&Event>, at: Time) -> f64 {
let first = events[0];
let second = events[1];
if first == second {
panic!("interpolate_linear given single event");
}
Self::sample_linear(first, second, at)
}
fn interpolate_linear_averaging(events: &Vec<&Event>, at: Time) -> f64 {
let first = events[1];
let second = events[2];
Self::interpolate_linear(&vec![first, second], at)
}
fn interpolate_hermite(events: &Vec<&Event>, at: Time) -> f64 {
println!("Interpolating hermite");
panic!("not implemented");
0.0
}
}
struct TimestampIterator {
end: f64,
cur: f64,
step: f64,
}
impl Iterator for TimestampIterator {
type Item = (f64, f64);
fn next(&mut self) -> Option<Self::Item> {
if self.cur == self.end {
None
} else if (self.end - self.cur) < self.step {
let r = (self.cur, self.end);
self.cur = self.end;
Some(r)
} else {
let r = (self.cur, self.cur + self.step);
self.cur += self.step;
Some(r)
}
}
}
fn iter_range(start: f64, end: f64, by: f64) -> TimestampIterator {
TimestampIterator {
end,
cur: start,
step: by,
}
}