use crate::{Accelerator2d, Domain2dError, InterpolationError, check_if_inbounds2d};
pub trait BuildInterpolator2d: Interpolation2d + Sized {
#[doc(alias = "gsl_interp2d_min_size")]
const MIN_SIZE: usize;
#[doc(alias = "gsl_interp2d_init")]
#[expect(clippy::missing_errors_doc, reason = "documented on the implementors")]
fn build(xa: &[f64], ya: &[f64], za: &[f64]) -> Result<Self, InterpolationError>;
}
#[expect(private_bounds, reason = "needed to make Box<dyn Interpolation> Clone")]
pub trait Interpolation2d: DynInterpolation2dClone + Send + Sync + 'static {
#[doc(alias = "gsl_interp2d_eval")]
#[doc(alias = "gsl_interp2d_eval_e")]
fn eval(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError> {
check_if_inbounds2d(xa, ya, x, y)?;
Ok(self.eval_extrap(xa, ya, za, x, y, acc))
}
#[doc(alias = "gsl_interp2d_eval_extrap")]
#[doc(alias = "gsl_interp2d_eval_extrap_e")]
fn eval_extrap(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> f64;
#[doc(alias = "gsl_interp2d_eval_deriv_x")]
#[doc(alias = "gsl_interp2d_eval_deriv_x_e")]
fn eval_deriv_x(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError>;
#[doc(alias = "gsl_interp2d_eval_deriv_y")]
#[doc(alias = "gsl_interp2d_eval_deriv_y_e")]
fn eval_deriv_y(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError>;
#[doc(alias = "gsl_interp2d_eval_deriv_xx")]
#[doc(alias = "gsl_interp2d_eval_deriv_xx_e")]
fn eval_deriv_xx(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError>;
#[doc(alias = "gsl_interp2d_eval_deriv_yy")]
#[doc(alias = "gsl_interp2d_eval_deriv_yy_e")]
fn eval_deriv_yy(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError>;
#[doc(alias = "gsl_interp2d_eval_deriv_xy")]
#[doc(alias = "gsl_interp2d_eval_deriv_xy_e")]
fn eval_deriv_xy(
&self,
xa: &[f64],
ya: &[f64],
za: &[f64],
x: f64,
y: f64,
acc: &mut Accelerator2d,
) -> Result<f64, Domain2dError>;
}
#[doc(alias = "gsl_interp2d_idx")]
#[must_use]
pub fn z_idx(i: usize, j: usize, xlen: usize, ylen: usize) -> usize {
if (i >= xlen) | (j >= ylen) {
panic!("z-index out of range")
} else {
j * xlen + i
}
}
#[doc(alias = "gsl_inter2d_set")]
pub fn z_set<T>(za: &mut [T], z: T, i: usize, j: usize, xlen: usize, ylen: usize) {
if (i >= xlen) | (j >= ylen) {
panic!("z-index out of range")
};
za[z_idx(i, j, xlen, ylen)] = z;
}
#[doc(alias = "gsl_inter2d_get")]
#[must_use]
pub fn z_get(za: &[f64], i: usize, j: usize, xlen: usize, ylen: usize) -> f64 {
if (i >= xlen) | (j >= ylen) {
panic!("z-index out of range")
};
za[z_idx(i, j, xlen, ylen)]
}
trait DynInterpolation2dClone {
fn clone_box(&self) -> Box<dyn Interpolation2d>;
}
impl<T> DynInterpolation2dClone for T
where
T: 'static + Interpolation2d + Clone,
{
fn clone_box(&self) -> Box<dyn Interpolation2d> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Interpolation2d> {
fn clone(&self) -> Self {
self.clone_box()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::*;
#[test]
fn dyn_clone() {
let xa = [0.0, 1.0, 2.0];
let ya = [0.0, 2.0, 4.0];
#[rustfmt::skip]
let za = [
0.0, 1.0, 2.0,
2.0, 3.0, 4.0,
4.0, 5.0, 6.0,
];
let interp: Box<dyn Interpolation2d> =
Box::new(BilinearInterpolator::build(&xa, &ya, &za).unwrap());
let _ = interp.clone();
}
}