diff --git a/CHANGELOG.md b/CHANGELOG.md index eb6a740..bfad977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,12 +18,12 @@ logarithmic spaced values. - added type aliases for common interpolators - make the `VectorExtensions` trait public - add `Interp1D::new_unchecked` and `Interp2D::new_unchecked` methods - - add biliniar extrapolation + - add bilinear extrapolation - impl `Default` for interpolation strategies # 0.3.0 - add 2d interpolation - - add biliniar interpolation strategy + - add bilinear interpolation strategy - rename `Strategy` to `Interp1DStrategy` and `StrategyBuilder` to `Interp1DStrategyBuilder` - make extrapolate filed of `Linear` private add `extrapolate(bool)` method instead. diff --git a/Cargo.toml b/Cargo.toml index 5a390e7..63c0ccc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" description = "Interpolation package for ndarray" repository = "https://github.com/jonasBoss/ndarray-interp" -keywords = ["interpolation", "multidimensional", "liniar", "biliniar", "cubic-spline"] +keywords = ["interpolation", "multidimensional", "linear", "bilinear", "cubic-spline"] categories = ["science", "algorithms", "mathematics"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 11130fe..5c0a52c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Interpolation crate for usage with the rust [ndarray](https://crates.io/crates ## Interpolation strategies - Linear interpolation with, and without extrapolation - Cubic spline interpolation [Wikipedia](https://en.wikipedia.org/wiki/Spline_interpolation) - - Biliniar interpolation with, and without extrapolation [Wikipedia](https://en.wikipedia.org/wiki/Bilinear_interpolation) + - Bilinear interpolation with, and without extrapolation [Wikipedia](https://en.wikipedia.org/wiki/Bilinear_interpolation) ## Planned Features - More interpolation strategies diff --git a/benches/bench_interp2d_query_dim.rs b/benches/bench_interp2d_query_dim.rs index 2e0e397..95442f4 100644 --- a/benches/bench_interp2d_query_dim.rs +++ b/benches/bench_interp2d_query_dim.rs @@ -1,12 +1,12 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::{Array, Array1, Axis}; -use ndarray_interp::interp2d::{Biliniar, Interp2D, Interp2DScalar}; +use ndarray_interp::interp2d::{Bilinear, Interp2D, Interp2DScalar}; use rand_extensions::RandArray; mod rand_extensions; -fn setup() -> (Interp2DScalar, Array1, Array1) { +fn setup() -> (Interp2DScalar, Array1, Array1) { let data = Array::from_rand(10_000, (0.0, 1.0), 42) .into_shape((100, 100)) .unwrap(); diff --git a/src/interp2d.rs b/src/interp2d.rs index 78eda50..62bf309 100644 --- a/src/interp2d.rs +++ b/src/interp2d.rs @@ -9,7 +9,7 @@ //! - [`Interp2DStrategyBuilder`] The trait used to specialize [`Interp2DBuilder`] to initialize the correct strategy //! //! # Strategies -//! - [`Biliniar`] Linear interpolation strategy +//! - [`Bilinear`] Linear interpolation strategy use std::{any::TypeId, fmt::Debug, ops::Sub}; @@ -29,7 +29,7 @@ use crate::{ mod aliases; mod strategies; pub use aliases::*; -pub use strategies::{Biliniar, Interp2DStrategy, Interp2DStrategyBuilder}; +pub use strategies::{Bilinear, Interp2DStrategy, Interp2DStrategyBuilder}; /// Two dimensional interpolator #[derive(Debug)] @@ -47,7 +47,7 @@ where strategy: Strat, } -impl Interp2D, OwnedRepr, D, Biliniar> +impl Interp2D, OwnedRepr, D, Bilinear> where Sd: Data, Sd::Elem: Num + PartialOrd + NumCast + Copy + Debug + Sub + Send, @@ -56,7 +56,7 @@ where /// Get the [Interp2DBuilder] pub fn builder( data: ArrayBase, - ) -> Interp2DBuilder, OwnedRepr, D, Biliniar> { + ) -> Interp2DBuilder, OwnedRepr, D, Bilinear> { Interp2DBuilder::new(data) } } @@ -379,7 +379,7 @@ where strategy: Strat, } -impl Interp2DBuilder, OwnedRepr, D, Biliniar> +impl Interp2DBuilder, OwnedRepr, D, Bilinear> where Sd: Data, Sd::Elem: Num + PartialOrd + NumCast + Copy + Debug + Sub, @@ -400,7 +400,7 @@ where x, y, data, - strategy: Biliniar::new(), + strategy: Bilinear::new(), } } } @@ -416,7 +416,7 @@ where Strat: Interp2DStrategyBuilder, { /// Set the interpolation strategy by provideing a [`Interp2DStrategyBuilder`]. - /// By default [`Biliniar`] is used. + /// By default [`Bilinear`] is used. pub fn strategy>( self, strategy: NewStrat, diff --git a/src/interp2d/strategies.rs b/src/interp2d/strategies.rs index 05df9cc..44f1f30 100644 --- a/src/interp2d/strategies.rs +++ b/src/interp2d/strategies.rs @@ -7,9 +7,9 @@ use crate::{BuilderError, InterpolateError}; use super::Interp2D; -mod biliniar; +mod bilinear; -pub use biliniar::Biliniar; +pub use bilinear::Bilinear; pub trait Interp2DStrategyBuilder where diff --git a/src/interp2d/strategies/biliniar.rs b/src/interp2d/strategies/bilinear.rs similarity index 68% rename from src/interp2d/strategies/biliniar.rs rename to src/interp2d/strategies/bilinear.rs index d114016..573f3e4 100644 --- a/src/interp2d/strategies/biliniar.rs +++ b/src/interp2d/strategies/bilinear.rs @@ -1,6 +1,6 @@ use std::{fmt::Debug, ops::Sub}; -use ndarray::{Data, Dimension, RemoveAxis, Zip}; +use ndarray::{Data, Dimension, RemoveAxis, Zip, RawData}; use num_traits::{Num, NumCast}; use crate::{interp1d::Linear, InterpolateError}; @@ -8,11 +8,12 @@ use crate::{interp1d::Linear, InterpolateError}; use super::{Interp2DStrategy, Interp2DStrategyBuilder}; #[derive(Debug)] -pub struct Biliniar { +pub struct Bilinear { extrapolate: bool, + allow_default: bool } -impl Interp2DStrategyBuilder for Biliniar +impl Interp2DStrategyBuilder for Bilinear where Sd: Data, Sd::Elem: Num + PartialOrd + NumCast + Copy + Debug + Sub + Send, @@ -20,6 +21,7 @@ where Sy: Data, D: Dimension + RemoveAxis, D::Smaller: RemoveAxis, + ::Elem: Default { const MINIMUM_DATA_LENGHT: usize = 2; @@ -35,7 +37,7 @@ where } } -impl Interp2DStrategy for Biliniar +impl Interp2DStrategy for Bilinear where Sd: Data, Sd::Elem: Num + PartialOrd + NumCast + Copy + Debug + Sub + Send, @@ -43,6 +45,7 @@ where Sy: Data, D: Dimension + RemoveAxis, D::Smaller: RemoveAxis, + ::Elem: Default { fn interp_into( &self, @@ -51,17 +54,29 @@ where x: ::Elem, y: ::Elem, ) -> Result<(), crate::InterpolateError> { - if !self.extrapolate && !interpolator.is_in_x_range(x) { + if self.extrapolate && self.allow_default { + return Err(InterpolateError::InvalidArguments(format!( + "cannot extrapolate if default is allowed" + ))); + } + if !self.extrapolate && !interpolator.is_in_x_range(x) && !self.allow_default { return Err(InterpolateError::OutOfBounds(format!( "x = {x:?} is not in range" ))); } - if !self.extrapolate && !interpolator.is_in_y_range(y) { + if !self.extrapolate && !interpolator.is_in_y_range(y) && !self.allow_default { return Err(InterpolateError::OutOfBounds(format!( "y = {y:?} is not in range" ))); } + // If out of bounds and allow_default, return default + if self.allow_default && (!interpolator.is_in_x_range(x) || !interpolator.is_in_y_range(y)) { + target.into_iter().for_each(|z| *z = Default::default()); + return Ok(()); + } + + // Otherwise, blend values... let (x_idx, y_idx) = interpolator.get_index_left_of(x, y); let (x1, y1, z11) = interpolator.index_point(x_idx, y_idx); let (_, _, z12) = interpolator.index_point(x_idx, y_idx + 1); @@ -82,18 +97,23 @@ where } } -impl Biliniar { +impl Bilinear { pub fn new() -> Self { - Biliniar { extrapolate: false } + Self { extrapolate: false, allow_default: false } } pub fn extrapolate(mut self, yes: bool) -> Self { self.extrapolate = yes; self } + + pub fn allow_default(mut self, value: bool) -> Self { + self.allow_default = value; + self + } } -impl Default for Biliniar { +impl Default for Bilinear { fn default() -> Self { Self::new() } diff --git a/src/lib.rs b/src/lib.rs index 725633e..77d0972 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,8 @@ pub enum BuilderError { pub enum InterpolateError { #[error("{0}")] OutOfBounds(String), + #[error("{0}")] + InvalidArguments(String), } /// cast `a` from type `A` to type `B` without any safety checks