use std::cell::RefCell;
use num::Float;
pub trait Coordinate: Float {
fn from_ratio(a: isize, b: usize) -> Self;
fn half(a: isize) -> Self;
}
pub trait Density: Default + Clone + Copy {
type F: Coordinate;
fn inside(&self) -> bool;
fn to_normal(a: &Self::F, b: &Self::F, c: &Self::F) -> [Self::F; 3];
fn interp(a: &Self, b: &Self, threshold: &Self) -> Self::F;
fn diff(&self, other: Self) -> Self::F;
fn shrink_factor() -> Self::F;
}
impl Coordinate for f32 {
fn from_ratio(a: isize, b: usize) -> Self {
a as f32 / b as f32
}
fn half(a: isize) -> Self {
0.5f32 * a as f32
}
}
impl Density for f32 {
type F = f32;
fn inside(&self) -> bool {
self > &0f32
}
fn to_normal(a: &Self, b: &Self, c: &Self) -> [f32; 3] {
let norm = (a * a + b * b + c * c).sqrt();
if norm > f32::EPSILON {
[-a / norm, -b / norm, -c / norm]
} else {
[0f32, 0f32, 0f32]
}
}
fn interp(a: &Self, b: &Self, threshold: &Self) -> f32 {
if (b - a).abs() > f32::EPSILON {
(threshold - a) / (b - a)
} else {
0.5f32
}
}
fn diff(&self, other: Self) -> Self::F {
self - other
}
fn shrink_factor() -> Self::F {
0.15
}
}
pub trait ScalarField<D, F> {
fn get_density(&self, x: F, y: F, z: F) -> D;
}
impl<D, F, FIELD> ScalarField<D, F> for &mut FIELD
where
FIELD: ScalarField<D, F> + ?Sized,
{
fn get_density(&self, x: F, y: F, z: F) -> D {
(**self).get_density(x, y, z)
}
}
pub struct ScalarFieldForFn<FN>(pub FN);
impl<D, F, FN> ScalarField<D, F> for ScalarFieldForFn<FN>
where
FN: Fn(F, F, F) -> D,
{
fn get_density(&self, x: F, y: F, z: F) -> D {
self.0(x, y, z)
}
}
pub struct ScalarFieldForFnMut<FN>(pub RefCell<FN>);
impl<D, F, FN> ScalarField<D, F> for ScalarFieldForFnMut<FN>
where
FN: FnMut(F, F, F) -> D,
{
fn get_density(&self, x: F, y: F, z: F) -> D {
self.0.borrow_mut()(x, y, z)
}
}