use super::*;
mod strategies;
#[cfg(test)]
mod tests;
const N: usize = 3;
pub type InterpData3D<D> = InterpData<D, N>;
pub type InterpData3DViewed<T> = InterpData3D<ViewRepr<T>>;
pub type InterpData3DOwned<T> = InterpData3D<OwnedRepr<T>>;
impl<D> InterpData3D<D>
where
D: Data + RawDataClone + Clone,
D::Elem: PartialOrd + Debug,
{
pub fn new(
x: ArrayBase<D, Ix1>,
y: ArrayBase<D, Ix1>,
z: ArrayBase<D, Ix1>,
f_xyz: ArrayBase<D, Ix3>,
) -> Result<Self, ValidateError> {
let data = Self {
grid: [x, y, z],
values: f_xyz,
};
data.validate()?;
Ok(data)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(
feature = "serde",
serde(bound(
serialize = "
D::Elem: Serialize,
S: Serialize,
",
deserialize = "
D: DataOwned,
D::Elem: Deserialize<'de>,
S: Deserialize<'de>,
"
))
)]
pub struct Interp3D<D, S>
where
D: Data + RawDataClone + Clone,
D::Elem: PartialEq + Debug,
S: Strategy3D<D> + Clone,
{
pub data: InterpData3D<D>,
pub strategy: S,
#[cfg_attr(feature = "serde", serde(default))]
pub extrapolate: Extrapolate<D::Elem>,
}
pub type Interp3DViewed<T, S> = Interp3D<ViewRepr<T>, S>;
pub type Interp3DOwned<T, S> = Interp3D<OwnedRepr<T>, S>;
extrapolate_impl!(Interp3D, Strategy3D);
partialeq_impl!(Interp3D, InterpData3D, Strategy3D);
impl<D, S> Interp3D<D, S>
where
D: Data + RawDataClone + Clone,
D::Elem: PartialOrd + Debug,
S: Strategy3D<D> + Clone,
{
pub fn new(
x: ArrayBase<D, Ix1>,
y: ArrayBase<D, Ix1>,
z: ArrayBase<D, Ix1>,
f_xyz: ArrayBase<D, Ix3>,
strategy: S,
extrapolate: Extrapolate<D::Elem>,
) -> Result<Self, ValidateError> {
let mut interpolator = Self {
data: InterpData3D::new(x, y, z, f_xyz)?,
strategy,
extrapolate,
};
interpolator.check_extrapolate(&interpolator.extrapolate)?;
interpolator.strategy.init(&interpolator.data)?;
Ok(interpolator)
}
pub fn view(&self) -> Interp3DViewed<&D::Elem, S>
where
S: for<'a> Strategy3D<ViewRepr<&'a D::Elem>>,
D::Elem: Clone,
{
Interp3DViewed {
data: self.data.view(),
strategy: self.strategy.clone(),
extrapolate: self.extrapolate.clone(),
}
}
pub fn into_owned(self) -> Interp3DOwned<D::Elem, S>
where
S: Strategy3D<OwnedRepr<D::Elem>>,
D::Elem: Clone,
{
Interp3DOwned {
data: self.data.into_owned(),
strategy: self.strategy.clone(),
extrapolate: self.extrapolate.clone(),
}
}
}
impl<D, S> Interpolator<D::Elem> for Interp3D<D, S>
where
D: Data + RawDataClone + Clone,
D::Elem: Num + Euclid + PartialOrd + Debug + Copy,
S: Strategy3D<D> + Clone,
{
#[inline]
fn ndim(&self) -> usize {
N
}
fn validate(&mut self) -> Result<(), ValidateError> {
self.check_extrapolate(&self.extrapolate)?;
self.data.validate()?;
self.strategy.init(&self.data)?;
Ok(())
}
fn interpolate(&self, point: &[D::Elem]) -> Result<D::Elem, InterpolateError> {
let point: &[D::Elem; N] = point
.try_into()
.map_err(|_| InterpolateError::PointLength(N))?;
let mut errors = Vec::new();
for dim in 0..N {
if !(self.data.grid[dim].first().unwrap()..=self.data.grid[dim].last().unwrap())
.contains(&&point[dim])
{
match &self.extrapolate {
Extrapolate::Enable => {}
Extrapolate::Fill(value) => return Ok(*value),
Extrapolate::Clamp => {
let clamped_point = std::array::from_fn(|i| {
*clamp(
&point[i],
self.data.grid[i].first().unwrap(),
self.data.grid[i].last().unwrap(),
)
});
return self.strategy.interpolate(&self.data, &clamped_point);
}
Extrapolate::Wrap => {
let wrapped_point = std::array::from_fn(|i| {
wrap(
point[i],
*self.data.grid[i].first().unwrap(),
*self.data.grid[i].last().unwrap(),
)
});
return self.strategy.interpolate(&self.data, &wrapped_point);
}
Extrapolate::Error => {
errors.push(format!(
"\n point[{dim}] = {:?} is out of bounds for grid[{dim}] = {:?}",
point[dim], self.data.grid[dim],
));
}
};
}
}
if !errors.is_empty() {
return Err(InterpolateError::ExtrapolateError(errors.join("")));
}
self.strategy.interpolate(&self.data, point)
}
fn set_extrapolate(&mut self, extrapolate: Extrapolate<D::Elem>) -> Result<(), ValidateError> {
self.check_extrapolate(&extrapolate)?;
self.extrapolate = extrapolate;
Ok(())
}
}
impl<D> Interp3D<D, Box<dyn Strategy3D<D>>>
where
D: Data + RawDataClone + Clone,
D::Elem: PartialEq + Debug,
{
pub fn set_strategy(&mut self, strategy: Box<dyn Strategy3D<D>>) -> Result<(), ValidateError> {
self.strategy = strategy;
self.check_extrapolate(&self.extrapolate)
}
}
impl<D> Interp3D<D, strategy::enums::Strategy3DEnum>
where
D: Data + RawDataClone + Clone,
D::Elem: Num + PartialOrd + Copy + Debug,
{
pub fn set_strategy(
&mut self,
strategy: impl Into<strategy::enums::Strategy3DEnum>,
) -> Result<(), ValidateError> {
self.strategy = strategy.into();
self.check_extrapolate(&self.extrapolate)
}
}