#[derive(Debug, Clone)]
pub struct DynamicTime {
pub scale_factor: f64,
ref_scale: f64,
offset: f64,
pub seconds: f64,
}
impl DynamicTime {
pub fn new() -> Self {
Self {
scale_factor: 1.0,
ref_scale: 1.0,
offset: 0.0,
seconds: 0.0,
}
}
pub fn update(&mut self, simtime: f64) {
self.seconds = simtime * self.ref_scale + self.offset;
}
pub fn update_offset(&mut self, simtime: f64) -> bool {
assert!(
self.scale_factor.is_finite(),
"scale_factor must be finite, got {}",
self.scale_factor
);
assert!(
simtime.is_finite(),
"simtime must be finite, got {}",
simtime
);
if self.ref_scale != self.scale_factor {
self.offset = self.seconds - (self.scale_factor * simtime);
let _direction_changed = self.ref_scale * self.scale_factor < 0.0;
self.ref_scale = self.scale_factor;
true } else {
false
}
}
}
impl Default for DynamicTime {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dyn_time_default_scale() {
let mut dyn_time = DynamicTime::new();
dyn_time.update(100.0);
assert!((dyn_time.seconds - 100.0).abs() < 1e-15);
}
#[test]
fn dyn_time_double_speed() {
let mut dyn_time = DynamicTime::new();
dyn_time.scale_factor = 2.0;
dyn_time.update_offset(0.0);
dyn_time.update(50.0);
assert!(
(dyn_time.seconds - 100.0).abs() < 1e-15,
"At 2x speed, 50s simtime should give 100s dyn, got {}",
dyn_time.seconds
);
}
#[test]
fn dyn_time_mid_sim_scale_change() {
let mut dyn_time = DynamicTime::new();
dyn_time.update(100.0);
assert!((dyn_time.seconds - 100.0).abs() < 1e-15);
dyn_time.scale_factor = 2.0;
let changed = dyn_time.update_offset(100.0);
assert!(changed);
dyn_time.update(150.0);
assert!(
(dyn_time.seconds - 200.0).abs() < 1e-15,
"Expected 200, got {}",
dyn_time.seconds
);
}
#[test]
fn dyn_time_reversal() {
let mut dyn_time = DynamicTime::new();
dyn_time.update(100.0);
dyn_time.scale_factor = -1.0;
dyn_time.update_offset(100.0);
dyn_time.update(200.0);
assert!(
dyn_time.seconds.abs() < 1e-15,
"Expected 0, got {}",
dyn_time.seconds
);
}
}