use std::collections::VecDeque;
use crate::data::PolyData;
#[derive(Debug, Clone)]
pub struct TemporalDataSetCache {
entries: VecDeque<(f64, PolyData)>,
capacity: usize,
}
impl TemporalDataSetCache {
pub fn new(capacity: usize) -> Self {
Self {
entries: VecDeque::with_capacity(capacity),
capacity: capacity.max(1),
}
}
pub fn insert(&mut self, time: f64, data: PolyData) {
if self.entries.len() >= self.capacity {
self.entries.pop_front();
}
self.entries.push_back((time, data));
}
pub fn get(&self, time: f64) -> Option<&PolyData> {
self.entries.iter().find(|(t, _)| (*t - time).abs() < 1e-15).map(|(_, d)| d)
}
pub fn get_nearest(&self, time: f64) -> Option<&PolyData> {
self.entries
.iter()
.min_by(|(a, _), (b, _)| {
(a - time).abs().partial_cmp(&(b - time).abs()).unwrap_or(std::cmp::Ordering::Equal)
})
.map(|(_, d)| d)
}
pub fn bracket(&self, time: f64) -> Option<(&PolyData, &PolyData, f64)> {
let mut before: Option<(f64, &PolyData)> = None;
let mut after: Option<(f64, &PolyData)> = None;
for (t, data) in &self.entries {
if *t <= time {
before = Some((*t, data));
}
if *t >= time && after.is_none() {
after = Some((*t, data));
}
}
match (before, after) {
(Some((t0, d0)), Some((t1, d1))) => {
let alpha = if (t1 - t0).abs() > 1e-15 { (time - t0) / (t1 - t0) } else { 0.0 };
Some((d0, d1, alpha))
}
_ => None,
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn times(&self) -> Vec<f64> {
self.entries.iter().map(|(t, _)| *t).collect()
}
}
#[derive(Debug, Clone)]
pub struct MeshTopologyCache {
last_num_points: usize,
last_num_cells: usize,
cached_data: Option<PolyData>,
}
impl MeshTopologyCache {
pub fn new() -> Self {
Self {
last_num_points: 0,
last_num_cells: 0,
cached_data: None,
}
}
pub fn update(&mut self, data: &PolyData) -> bool {
let np = data.points.len();
let nc = data.polys.num_cells();
let changed = np != self.last_num_points || nc != self.last_num_cells;
self.last_num_points = np;
self.last_num_cells = nc;
self.cached_data = Some(data.clone());
changed
}
pub fn get(&self) -> Option<&PolyData> {
self.cached_data.as_ref()
}
pub fn force_static(&self, data: &PolyData) -> Option<PolyData> {
let cached = self.cached_data.as_ref()?;
let mut result = cached.clone();
*result.point_data_mut() = data.point_data().clone();
*result.cell_data_mut() = data.cell_data().clone();
Some(result)
}
}
impl Default for MeshTopologyCache {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_pd(n: usize) -> PolyData {
let pts: Vec<[f64; 3]> = (0..n).map(|i| [i as f64, 0.0, 0.0]).collect();
PolyData::from_triangles(pts, vec![])
}
#[test]
fn cache_insert_and_get() {
let mut cache = TemporalDataSetCache::new(3);
cache.insert(0.0, sample_pd(3));
cache.insert(1.0, sample_pd(4));
cache.insert(2.0, sample_pd(5));
assert_eq!(cache.len(), 3);
assert!(cache.get(1.0).is_some());
assert_eq!(cache.get(1.0).unwrap().points.len(), 4);
}
#[test]
fn cache_eviction() {
let mut cache = TemporalDataSetCache::new(2);
cache.insert(0.0, sample_pd(3));
cache.insert(1.0, sample_pd(4));
cache.insert(2.0, sample_pd(5));
assert_eq!(cache.len(), 2);
assert!(cache.get(0.0).is_none()); assert!(cache.get(1.0).is_some());
}
#[test]
fn bracket_interpolation() {
let mut cache = TemporalDataSetCache::new(3);
cache.insert(0.0, sample_pd(3));
cache.insert(2.0, sample_pd(5));
let (_, _, alpha) = cache.bracket(1.0).unwrap();
assert!((alpha - 0.5).abs() < 1e-10);
}
#[test]
fn mesh_topology_cache() {
let mut mc = MeshTopologyCache::new();
let pd1 = sample_pd(3);
assert!(mc.update(&pd1)); assert!(!mc.update(&pd1));
let pd2 = sample_pd(5);
assert!(mc.update(&pd2)); }
}