use intervaltree::IntervalTree;
use std::cmp::Ordering;
#[derive(PartialEq, Clone, Copy, Debug)]
struct IntervalFloat(f32);
impl Eq for IntervalFloat {}
impl PartialOrd for IntervalFloat {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for IntervalFloat {
fn cmp(&self, other: &Self) -> Ordering {
self.0.partial_cmp(&other.0).unwrap_or(Ordering::Equal)
}
}
#[derive(Clone, Debug)]
pub struct Interval<T> {
pub start: f32,
pub end: f32,
pub data: T,
}
impl<T> Interval<T> {
pub fn progress(&self, absolute_time: f32) -> f32 {
if self.end <= self.start {
return 1.0;
}
((absolute_time - self.start) / (self.end - self.start)).clamp(0.0, 1.0)
}
pub fn contains(&self, time: f32) -> bool {
time >= self.start && time < self.end
}
}
#[derive(Clone, Debug)]
pub struct Timeline<T> {
tree: Option<IntervalTree<IntervalFloat, T>>,
pending: Vec<Interval<T>>,
duration: f32,
}
impl<T: Clone> Default for Timeline<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone> Timeline<T> {
pub fn new() -> Self {
Self {
tree: None,
pending: Vec::new(),
duration: 0.0,
}
}
pub fn add(&mut self, start: f32, end: f32, data: T) {
self.duration = self.duration.max(end);
self.pending.push(Interval { start, end, data });
self.tree = None;
}
fn ensure_tree(&mut self) {
if self.tree.is_none() && !self.pending.is_empty() {
let elements: Vec<_> = self
.pending
.iter()
.map(|i| (IntervalFloat(i.start)..IntervalFloat(i.end), i.data.clone()))
.collect();
self.tree = Some(IntervalTree::from_iter(elements));
}
}
pub fn active_at(&self, time: f32) -> Vec<Interval<T>> {
if let Some(tree) = &self.tree {
let t = IntervalFloat(time);
tree.query(t..IntervalFloat(time + 0.00001))
.map(|element| Interval {
start: element.range.start.0,
end: element.range.end.0,
data: element.value.clone(),
})
.collect()
} else {
self.pending
.iter()
.filter(|i| i.contains(time))
.cloned()
.collect()
}
}
pub fn find_active(&self, time: f32) -> Option<Interval<T>> {
if let Some(tree) = &self.tree {
let t = IntervalFloat(time);
tree.query(t..IntervalFloat(time + 0.00001))
.next()
.map(|element| Interval {
start: element.range.start.0,
end: element.range.end.0,
data: element.value.clone(),
})
} else {
self.pending.iter().find(|i| i.contains(time)).cloned()
}
}
pub fn find_in_range(&self, start: f32, end: f32) -> Vec<Interval<T>> {
if let Some(tree) = &self.tree {
let s = IntervalFloat(start);
let e = IntervalFloat(end);
tree.query(s..e)
.filter(|element| element.range.start.0 >= start && element.range.start.0 < end)
.map(|element| Interval {
start: element.range.start.0,
end: element.range.end.0,
data: element.value.clone(),
})
.collect()
} else {
self.pending
.iter()
.filter(|i| i.start >= start && i.start < end)
.cloned()
.collect()
}
}
pub fn duration(&self) -> f32 {
self.duration
}
pub fn finalize(&mut self) {
self.ensure_tree();
}
}