use crate::vector2::Vector2D;
use std::sync::{RwLock, Arc};
use crate::field2::Field2;
use crate::scalar_field2::ScalarField2;
pub struct CustomScalarField2 {
_custom_function: fn(&Vector2D) -> f64,
_custom_gradient_function: Option<fn(&Vector2D) -> Vector2D>,
_custom_laplacian_function: Option<fn(&Vector2D) -> f64>,
_resolution: f64,
}
impl CustomScalarField2 {
pub fn new(custom_function: fn(&Vector2D) -> f64,
custom_gradient_function: Option<fn(&Vector2D) -> Vector2D>,
custom_laplacian_function: Option<fn(&Vector2D) -> f64>,
derivative_resolution: Option<f64>) -> CustomScalarField2 {
return CustomScalarField2 {
_custom_function: custom_function,
_custom_gradient_function: custom_gradient_function,
_custom_laplacian_function: custom_laplacian_function,
_resolution: derivative_resolution.unwrap_or(1.0e-3),
};
}
pub fn builder() -> Builder {
return Builder::new();
}
}
impl Field2 for CustomScalarField2 {}
impl ScalarField2 for CustomScalarField2 {
fn sample(&self, x: &Vector2D) -> f64 {
return (self._custom_function)(x);
}
fn gradient(&self, x: &Vector2D) -> Vector2D {
return match self._custom_gradient_function {
None => {
let left = (self._custom_function)(&(*x - Vector2D::new(0.5 * self._resolution, 0.0)));
let right = (self._custom_function)(&(*x + Vector2D::new(0.5 * self._resolution, 0.0)));
let bottom = (self._custom_function)(&(*x - Vector2D::new(0.0, 0.5 * self._resolution)));
let top = (self._custom_function)(&(*x + Vector2D::new(0.0, 0.5 * self._resolution)));
Vector2D::new(
(right - left) / self._resolution,
(top - bottom) / self._resolution)
}
Some(func) => {
func(x)
}
};
}
fn laplacian(&self, x: &Vector2D) -> f64 {
return match self._custom_laplacian_function {
None => {
let center = (self._custom_function)(x);
let left = (self._custom_function)(&(*x - Vector2D::new(0.5 * self._resolution, 0.0)));
let right = (self._custom_function)(&(*x + Vector2D::new(0.5 * self._resolution, 0.0)));
let bottom = (self._custom_function)(&(*x - Vector2D::new(0.0, 0.5 * self._resolution)));
let top = (self._custom_function)(&(*x + Vector2D::new(0.0, 0.5 * self._resolution)));
(left + right + bottom + top - 4.0 * center)
/ (self._resolution * self._resolution)
}
Some(func) => {
func(x)
}
};
}
}
pub type CustomScalarField2Ptr = Arc<RwLock<CustomScalarField2>>;
pub struct Builder {
_custom_function: Option<fn(&Vector2D) -> f64>,
_custom_gradient_function: Option<fn(&Vector2D) -> Vector2D>,
_custom_laplacian_function: Option<fn(&Vector2D) -> f64>,
_resolution: f64,
}
impl Builder {
pub fn with_function(&mut self, func: fn(&Vector2D) -> f64) -> &mut Self {
self._custom_function = Some(func);
return self;
}
pub fn with_gradient_function(&mut self, func: fn(&Vector2D) -> Vector2D) -> &mut Self {
self._custom_gradient_function = Some(func);
return self;
}
pub fn with_laplacian_function(&mut self, func: fn(&Vector2D) -> f64) -> &mut Self {
self._custom_laplacian_function = Some(func);
return self;
}
pub fn with_derivative_resolution(&mut self, resolution: f64) -> &mut Self {
self._resolution = resolution;
return self;
}
pub fn build(&mut self) -> CustomScalarField2 {
return CustomScalarField2::new(self._custom_function.unwrap(),
self._custom_gradient_function,
self._custom_laplacian_function,
Some(self._resolution));
}
pub fn make_shared(&mut self) -> CustomScalarField2Ptr {
return CustomScalarField2Ptr::new(RwLock::new(self.build()));
}
pub fn new() -> Builder {
return Builder {
_custom_function: None,
_custom_gradient_function: None,
_custom_laplacian_function: None,
_resolution: 1.0e-3,
};
}
}