use crate::transform2::Transform2;
use crate::vector2::Vector2D;
use crate::bounding_box2::BoundingBox2D;
use crate::ray2::Ray2D;
use crate::surface2::*;
use crate::implicit_surface2::ImplicitSurface2;
use std::sync::{RwLock, Arc};
pub struct CustomImplicitSurface2 {
_func: fn(&Vector2D) -> f64,
_domain: BoundingBox2D,
_resolution: f64,
_ray_marching_resolution: f64,
_max_num_of_iterations: usize,
pub surface_data: Surface2Data,
}
impl CustomImplicitSurface2 {
pub fn new(func: fn(&Vector2D) -> f64,
domain: Option<BoundingBox2D>,
resolution: Option<f64>,
ray_marching_resolution: Option<f64>,
number_of_iterations: Option<usize>,
transform: Option<Transform2>,
is_normal_flipped: Option<bool>) -> CustomImplicitSurface2 {
return CustomImplicitSurface2 {
_func: func,
_domain: domain.unwrap_or(BoundingBox2D::new_default()),
_resolution: resolution.unwrap_or(1.0e-3),
_ray_marching_resolution: ray_marching_resolution.unwrap_or(1.0e-6),
_max_num_of_iterations: number_of_iterations.unwrap_or(5),
surface_data: Surface2Data::new(transform, is_normal_flipped),
};
}
pub fn builder() -> Builder {
return Builder::new();
}
pub fn gradient_local(&self, x: &Vector2D) -> Vector2D {
let left = (self._func)(&(*x - Vector2D::new(0.5 * self._resolution, 0.0)));
let right = (self._func)(&(*x + Vector2D::new(0.5 * self._resolution, 0.0)));
let bottom = (self._func)(&(*x - Vector2D::new(0.0, 0.5 * self._resolution)));
let top = (self._func)(&(*x + Vector2D::new(0.0, 0.5 * self._resolution)));
return Vector2D::new((right - left) / self._resolution, (top - bottom) / self._resolution);
}
}
impl Surface2 for CustomImplicitSurface2 {
fn closest_point_local(&self, other_point: &Vector2D) -> Vector2D {
let mut pt = crate::vector2::clamp(other_point, &self._domain.lower_corner, &self._domain.upper_corner);
for _ in 0..self._max_num_of_iterations {
let sdf = self.signed_distance_local(&pt);
if f64::abs(sdf) < f64::EPSILON {
break;
}
let g = self.gradient_local(&pt);
pt = pt - g * sdf;
}
return pt;
}
fn bounding_box_local(&self) -> BoundingBox2D {
return self._domain.clone();
}
fn closest_intersection_local(&self, ray: &Ray2D) -> SurfaceRayIntersection2 {
let mut result = SurfaceRayIntersection2::new();
let intersection = self._domain.closest_intersection(ray);
if intersection.is_intersecting {
let t_start;
let t_end;
if intersection.t_far == f64::MAX {
t_start = 0.0;
t_end = intersection.t_near;
} else {
t_start = intersection.t_near;
t_end = intersection.t_far;
}
let mut t = t_start;
let mut t_prev = t;
let mut pt = ray.point_at(t);
let mut prev_phi = (self._func)(&pt);
while t <= t_end {
pt = ray.point_at(t);
let new_phi = (self._func)(&pt);
let new_phi_abs = f64::abs(new_phi);
if new_phi * prev_phi < 0.0 {
let frac = prev_phi / (prev_phi - new_phi);
let t_sub = t_prev + self._ray_marching_resolution * frac;
result.is_intersecting = true;
result.distance = t_sub;
result.point = ray.point_at(t_sub);
result.normal = self.gradient_local(&result.point);
if result.normal.length() > 0.0 {
result.normal.normalize();
}
return result;
}
t_prev = t;
t += f64::max(new_phi_abs, self._ray_marching_resolution);
prev_phi = new_phi;
}
}
return result;
}
fn closest_normal_local(&self, other_point: &Vector2D) -> Vector2D {
let pt = self.closest_point_local(other_point);
let g = self.gradient_local(&pt);
return if g.length_squared() > 0.0 {
g.normalized()
} else {
g
};
}
fn intersects_local(&self, ray: &Ray2D) -> bool {
let intersection = self._domain.closest_intersection(ray);
if intersection.is_intersecting {
let t_start;
let t_end;
if intersection.t_far == f64::MAX {
t_start = 0.0;
t_end = intersection.t_near;
} else {
t_start = intersection.t_near;
t_end = intersection.t_far;
}
let mut t = t_start;
let mut pt = ray.point_at(t);
let mut prev_phi = (self._func)(&pt);
while t <= t_end {
pt = ray.point_at(t);
let new_phi = (self._func)(&pt);
let new_phi_abs = f64::abs(new_phi);
if new_phi * prev_phi < 0.0 {
return true;
}
t += f64::max(new_phi_abs, self._ray_marching_resolution);
prev_phi = new_phi;
}
}
return false;
}
fn view(&self) -> &Surface2Data {
return &self.surface_data;
}
}
impl ImplicitSurface2 for CustomImplicitSurface2 {
fn signed_distance_local(&self, other_point: &Vector2D) -> f64 {
return (self._func)(other_point);
}
}
pub type CustomImplicitSurface2Ptr = Arc<RwLock<CustomImplicitSurface2>>;
pub struct Builder {
_func: Option<fn(&Vector2D) -> f64>,
_domain: BoundingBox2D,
_resolution: f64,
_ray_marching_resolution: f64,
_max_num_of_iterations: usize,
_surface_data: Surface2Data,
}
impl Builder {
pub fn with_signed_distance_function(&mut self, func: fn(&Vector2D) -> f64) -> &mut Self {
self._func = Some(func);
return self;
}
pub fn with_domain(&mut self, domain: BoundingBox2D) -> &mut Self {
self._domain = domain;
return self;
}
pub fn with_resolution(&mut self, resolution: f64) -> &mut Self {
self._resolution = resolution;
return self;
}
pub fn with_ray_marching_resolution(&mut self, ray_marching_resolution: f64) -> &mut Self {
self._ray_marching_resolution = ray_marching_resolution;
return self;
}
pub fn with_max_number_of_iterations(&mut self, num_iter: usize) -> &mut Self {
self._max_num_of_iterations = num_iter;
return self;
}
pub fn build(&mut self) -> CustomImplicitSurface2 {
return CustomImplicitSurface2::new(self._func.unwrap(),
Some(self._domain.clone()),
Some(self._resolution),
Some(self._ray_marching_resolution),
Some(self._max_num_of_iterations),
Some(self._surface_data.transform.clone()),
Some(self._surface_data.is_normal_flipped));
}
pub fn make_shared(&mut self) -> CustomImplicitSurface2Ptr {
return CustomImplicitSurface2Ptr::new(RwLock::new(self.build()));
}
pub fn new() -> Builder {
return Builder {
_func: None,
_domain: BoundingBox2D::new_default(),
_resolution: 1.0e-3,
_ray_marching_resolution: 1.0e-6,
_max_num_of_iterations: 5,
_surface_data: Surface2Data::new(None, None),
};
}
}
impl SurfaceBuilderBase2 for Builder {
fn view(&mut self) -> &mut Surface2Data {
return &mut self._surface_data;
}
}