use crate::data::PolyData;
#[derive(Debug, Clone)]
pub struct TemporalDataSet {
steps: Vec<(f64, PolyData)>,
}
impl TemporalDataSet {
pub fn new() -> Self {
Self { steps: Vec::new() }
}
pub fn add_step(&mut self, time: f64, data: PolyData) {
self.steps.push((time, data));
self.steps.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
}
pub fn num_steps(&self) -> usize {
self.steps.len()
}
pub fn time_range(&self) -> Option<[f64; 2]> {
if self.steps.is_empty() { return None; }
Some([self.steps.first().unwrap().0, self.steps.last().unwrap().0])
}
pub fn times(&self) -> Vec<f64> {
self.steps.iter().map(|(t, _)| *t).collect()
}
pub fn step(&self, idx: usize) -> Option<&PolyData> {
self.steps.get(idx).map(|(_, pd)| pd)
}
pub fn at_time(&self, time: f64) -> Option<&PolyData> {
if self.steps.is_empty() { return None; }
let idx = self.steps.iter()
.enumerate()
.min_by(|(_, (ta, _)), (_, (tb, _))| {
(ta - time).abs().partial_cmp(&(tb - time).abs()).unwrap()
})
.map(|(i, _)| i)?;
Some(&self.steps[idx].1)
}
pub fn bracket(&self, time: f64) -> Option<(&PolyData, &PolyData, f64)> {
if self.steps.len() < 2 { return None; }
for i in 0..self.steps.len() - 1 {
let (t0, pd0) = &self.steps[i];
let (t1, pd1) = &self.steps[i + 1];
if time >= *t0 && time <= *t1 {
let frac = if (t1 - t0).abs() > 1e-15 {
(time - t0) / (t1 - t0)
} else {
0.0
};
return Some((pd0, pd1, frac));
}
}
None
}
pub fn interpolate_positions(&self, time: f64) -> Option<PolyData> {
let (pd0, pd1, t) = self.bracket(time)?;
if pd0.points.len() != pd1.points.len() { return None; }
let mut result = pd0.clone();
for i in 0..result.points.len() {
let p0 = pd0.points.get(i);
let p1 = pd1.points.get(i);
result.points.set(i, [
p0[0] + t * (p1[0] - p0[0]),
p0[1] + t * (p1[1] - p0[1]),
p0[2] + t * (p1[2] - p0[2]),
]);
}
Some(result)
}
}
impl Default for TemporalDataSet {
fn default() -> Self { Self::new() }
}
#[cfg(test)]
mod tests {
use super::*;
fn make_pd(x_offset: f64) -> PolyData {
PolyData::from_triangles(
vec![[x_offset, 0.0, 0.0], [x_offset + 1.0, 0.0, 0.0], [x_offset, 1.0, 0.0]],
vec![[0, 1, 2]],
)
}
#[test]
fn basic_temporal() {
let mut ts = TemporalDataSet::new();
ts.add_step(0.0, make_pd(0.0));
ts.add_step(1.0, make_pd(5.0));
assert_eq!(ts.num_steps(), 2);
assert_eq!(ts.time_range(), Some([0.0, 1.0]));
}
#[test]
fn at_time_nearest() {
let mut ts = TemporalDataSet::new();
ts.add_step(0.0, make_pd(0.0));
ts.add_step(1.0, make_pd(5.0));
let pd = ts.at_time(0.3).unwrap();
assert!((pd.points.get(0)[0]).abs() < 1e-10); }
#[test]
fn bracket() {
let mut ts = TemporalDataSet::new();
ts.add_step(0.0, make_pd(0.0));
ts.add_step(1.0, make_pd(10.0));
let (_, _, frac) = ts.bracket(0.5).unwrap();
assert!((frac - 0.5).abs() < 1e-10);
}
#[test]
fn interpolate() {
let mut ts = TemporalDataSet::new();
ts.add_step(0.0, make_pd(0.0));
ts.add_step(1.0, make_pd(10.0));
let interp = ts.interpolate_positions(0.5).unwrap();
assert!((interp.points.get(0)[0] - 5.0).abs() < 1e-10);
}
}