use crate::vector3::Vector3D;
use std::sync::{RwLock, Arc};
use crate::field3::Field3;
use crate::scalar_field3::ScalarField3;
pub struct CustomScalarField3 {
_custom_function: fn(&Vector3D) -> f64,
_custom_gradient_function: Option<fn(&Vector3D) -> Vector3D>,
_custom_laplacian_function: Option<fn(&Vector3D) -> f64>,
_resolution: f64,
}
impl CustomScalarField3 {
pub fn new(custom_function: fn(&Vector3D) -> f64,
custom_gradient_function: Option<fn(&Vector3D) -> Vector3D>,
custom_laplacian_function: Option<fn(&Vector3D) -> f64>,
derivative_resolution: Option<f64>) -> CustomScalarField3 {
return CustomScalarField3 {
_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 Field3 for CustomScalarField3 {}
impl ScalarField3 for CustomScalarField3 {
fn sample(&self, x: &Vector3D) -> f64 {
return (self._custom_function)(x);
}
fn gradient(&self, x: &Vector3D) -> Vector3D {
return match self._custom_gradient_function {
None => {
let left
= (self._custom_function)(&(*x - Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
let right
= (self._custom_function)(&(*x + Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
let bottom
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
let top
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
let back
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
let front
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
return Vector3D::new(
(right - left) / self._resolution,
(top - bottom) / self._resolution,
(front - back) / self._resolution);
}
Some(func) => {
func(x)
}
};
}
fn laplacian(&self, x: &Vector3D) -> f64 {
return match self._custom_laplacian_function {
None => {
let center = (self._custom_function)(x);
let left
= (self._custom_function)(&(*x - Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
let right
= (self._custom_function)(&(*x + Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
let bottom
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
let top
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
let back
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
let front
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
return (left + right + bottom + top + back + front - 6.0 * center)
/ (self._resolution * self._resolution);
}
Some(func) => {
func(x)
}
};
}
}
pub type CustomScalarField3Ptr = Arc<RwLock<CustomScalarField3>>;
pub struct Builder {
_custom_function: Option<fn(&Vector3D) -> f64>,
_custom_gradient_function: Option<fn(&Vector3D) -> Vector3D>,
_custom_laplacian_function: Option<fn(&Vector3D) -> f64>,
_resolution: f64,
}
impl Builder {
pub fn with_function(&mut self, func: fn(&Vector3D) -> f64) -> &mut Self {
self._custom_function = Some(func);
return self;
}
pub fn with_gradient_function(&mut self, func: fn(&Vector3D) -> Vector3D) -> &mut Self {
self._custom_gradient_function = Some(func);
return self;
}
pub fn with_laplacian_function(&mut self, func: fn(&Vector3D) -> 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) -> CustomScalarField3 {
return CustomScalarField3::new(self._custom_function.unwrap(),
self._custom_gradient_function,
self._custom_laplacian_function,
Some(self._resolution));
}
pub fn make_shared(&mut self) -> CustomScalarField3Ptr {
return CustomScalarField3Ptr::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,
};
}
}