use crate::Real;
use crate::error::KrigingError;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SpaceTimeCoord<C> {
pub spatial: C,
pub time: Real,
}
impl<C> SpaceTimeCoord<C> {
#[inline]
pub const fn new(spatial: C, time: Real) -> Self {
Self { spatial, time }
}
pub fn try_new(spatial: C, time: Real) -> Result<Self, KrigingError> {
if !time.is_finite() {
return Err(KrigingError::InvalidInput(format!(
"time must be finite, got {time}"
)));
}
Ok(Self { spatial, time })
}
}
#[inline]
pub(crate) fn temporal_distance(a: Real, b: Real) -> Real {
(a - b).abs()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::distance::GeoCoord;
#[test]
fn try_new_accepts_finite_time() {
let coord = SpaceTimeCoord::try_new(GeoCoord::try_new(0.0, 0.0).unwrap(), 1.5).unwrap();
assert_eq!(coord.time, 1.5);
}
#[test]
fn try_new_rejects_nan_and_infinity() {
let coord = GeoCoord::try_new(0.0, 0.0).unwrap();
assert!(SpaceTimeCoord::try_new(coord, Real::NAN).is_err());
assert!(SpaceTimeCoord::try_new(coord, Real::INFINITY).is_err());
assert!(SpaceTimeCoord::try_new(coord, Real::NEG_INFINITY).is_err());
}
#[test]
fn temporal_distance_is_absolute() {
assert_eq!(temporal_distance(3.0, 1.0), 2.0);
assert_eq!(temporal_distance(1.0, 3.0), 2.0);
assert_eq!(temporal_distance(-2.0, 5.0), 7.0);
}
}