use crate::vector3::Vector3D;
use crate::field3::Field3;
use crate::vector_field3::VectorField3;
use std::sync::{RwLock, Arc};
pub struct CustomVectorField3 {
_custom_function: fn(&Vector3D) -> Vector3D,
_custom_divergence_function: Option<fn(&Vector3D) -> f64>,
_custom_curl_function: Option<fn(&Vector3D) -> Vector3D>,
_resolution: f64,
}
impl CustomVectorField3 {
pub fn new(custom_function: fn(&Vector3D) -> Vector3D,
custom_divergence_function: Option<fn(&Vector3D) -> f64>,
custom_curl_function: Option<fn(&Vector3D) -> Vector3D>,
derivative_resolution: Option<f64>) -> CustomVectorField3 {
return CustomVectorField3 {
_custom_function: custom_function,
_custom_divergence_function: custom_divergence_function,
_custom_curl_function: custom_curl_function,
_resolution: derivative_resolution.unwrap_or(1.0e-3),
};
}
pub fn builder() -> Builder {
return Builder::new();
}
}
impl Field3 for CustomVectorField3 {}
impl VectorField3 for CustomVectorField3 {
fn sample(&self, x: &Vector3D) -> Vector3D {
return (self._custom_function)(x);
}
fn divergence(&self, x: &Vector3D) -> f64 {
return match self._custom_divergence_function {
None => {
let left
= (self._custom_function)(&(*x - Vector3D::new(0.5 * self._resolution, 0.0, 0.0))).x;
let right
= (self._custom_function)(&(*x + Vector3D::new(0.5 * self._resolution, 0.0, 0.0))).x;
let bottom
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.5 * self._resolution, 0.0))).y;
let top
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.5 * self._resolution, 0.0))).y;
let back
= (self._custom_function)(&(*x - Vector3D::new(0.0, 0.0, 0.5 * self._resolution))).z;
let front
= (self._custom_function)(&(*x + Vector3D::new(0.0, 0.0, 0.5 * self._resolution))).z;
(right - left + top - bottom + front - back) / self._resolution
}
Some(func) => {
func(x)
}
};
}
fn curl(&self, x: &Vector3D) -> Vector3D {
return match self._custom_curl_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)));
let fx_ym = bottom.x;
let fx_yp = top.x;
let fx_zm = back.x;
let fx_zp = front.x;
let fy_xm = left.y;
let fy_xp = right.y;
let fy_zm = back.y;
let fy_zp = front.y;
let fz_xm = left.z;
let fz_xp = right.z;
let fz_ym = bottom.z;
let fz_yp = top.z;
Vector3D::new(
(fz_yp - fz_ym) - (fy_zp - fy_zm),
(fx_zp - fx_zm) - (fz_xp - fz_xm),
(fy_xp - fy_xm) - (fx_yp - fx_ym)) / self._resolution
}
Some(func) => {
func(x)
}
};
}
}
pub type CustomVectorField3Ptr = Arc<RwLock<CustomVectorField3>>;
pub struct Builder {
_custom_function: Option<fn(&Vector3D) -> Vector3D>,
_custom_divergence_function: Option<fn(&Vector3D) -> f64>,
_custom_curl_function: Option<fn(&Vector3D) -> Vector3D>,
_resolution: f64,
}
impl Builder {
pub fn with_function(&mut self,
func: fn(&Vector3D) -> Vector3D) -> &mut Self {
self._custom_function = Some(func);
return self;
}
pub fn with_divergence_function(&mut self,
func: fn(&Vector3D) -> f64) -> &mut Self {
self._custom_divergence_function = Some(func);
return self;
}
pub fn with_curl_function(&mut self,
func: fn(&Vector3D) -> Vector3D) -> &mut Self {
self._custom_curl_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) -> CustomVectorField3 {
return CustomVectorField3::new(self._custom_function.unwrap(),
self._custom_divergence_function,
self._custom_curl_function,
Some(self._resolution));
}
pub fn make_shared(&mut self) -> CustomVectorField3Ptr {
return CustomVectorField3Ptr::new(RwLock::new(self.build()));
}
pub fn new() -> Builder {
return Builder {
_custom_function: None,
_custom_divergence_function: None,
_custom_curl_function: None,
_resolution: 1.0e-3,
};
}
}