use crate::vector3::Vector3D;
use crate::bounding_box3::BoundingBox3D;
use crate::ray3::Ray3D;
use crate::transform3::Transform3;
use crate::quaternion::QuaternionD;
use std::sync::{RwLock, Arc};
pub struct SurfaceRayIntersection3 {
pub is_intersecting: bool,
pub distance: f64,
pub point: Vector3D,
pub normal: Vector3D,
}
impl SurfaceRayIntersection3 {
pub fn new() -> SurfaceRayIntersection3 {
return SurfaceRayIntersection3 {
is_intersecting: false,
distance: f64::MAX,
point: Vector3D::new_default(),
normal: Vector3D::new_default(),
};
}
}
pub struct Surface3Data {
pub transform: Transform3,
pub is_normal_flipped: bool,
}
impl Surface3Data {
pub fn new(transform: Option<Transform3>,
is_normal_flipped: Option<bool>) -> Surface3Data {
return Surface3Data {
transform: transform.unwrap_or(Transform3::new_default()),
is_normal_flipped: is_normal_flipped.unwrap_or(false),
};
}
}
pub trait Surface3 {
fn closest_point_local(&self, other_point: &Vector3D) -> Vector3D;
fn bounding_box_local(&self) -> BoundingBox3D;
fn closest_intersection_local(&self, ray: &Ray3D) -> SurfaceRayIntersection3;
fn closest_normal_local(&self, other_point: &Vector3D) -> Vector3D;
fn intersects_local(&self, ray_local: &Ray3D) -> bool {
let result = self.closest_intersection_local(ray_local);
return result.is_intersecting;
}
fn closest_distance_local(&self, other_point_local: &Vector3D) -> f64 {
return other_point_local.distance_to(self.closest_point_local(other_point_local));
}
fn is_inside_local(&self, other_point_local: &Vector3D) -> bool {
let cp_local = self.closest_point_local(other_point_local);
let normal_local = self.closest_normal_local(other_point_local);
return (*other_point_local - cp_local).dot(&normal_local) < 0.0;
}
fn closest_point(&self, other_point: &Vector3D) -> Vector3D {
return self.view().transform.to_world_vec(&self.closest_point_local(
&self.view().transform.to_local_vec(&other_point)));
}
fn bounding_box(&self) -> BoundingBox3D {
return self.view().transform.to_world_aabb(&self.bounding_box_local());
}
fn intersects(&self, ray: &Ray3D) -> bool {
return self.intersects_local(&self.view().transform.to_local_ray(&ray));
}
fn closest_distance(&self, other_point: &Vector3D) -> f64 {
return self.closest_distance_local(&self.view().transform.to_local_vec(&other_point));
}
fn closest_intersection(&self, ray: &Ray3D) -> SurfaceRayIntersection3 {
let mut result = self.closest_intersection_local(
&self.view().transform.to_local_ray(&ray));
result.point = self.view().transform.to_world_vec(&result.point);
result.normal = self.view().transform.to_world_direction(&result.normal);
match self.view().is_normal_flipped {
true => result.normal *= -1.0,
_ => {}
}
return result;
}
fn closest_normal(&self, other_point: &Vector3D) -> Vector3D {
let mut result = self.view().transform.to_world_direction(
&self.closest_normal_local(
&self.view().transform.to_local_vec(&other_point)));
match self.view().is_normal_flipped {
true => result *= -1.0,
_ => {}
}
return result;
}
fn update_query_engine(&self) {}
fn is_bounded(&self) -> bool {
return true;
}
fn is_valid_geometry(&self) -> bool {
return true;
}
fn is_inside(&self, other_point: &Vector3D) -> bool {
return self.view().is_normal_flipped == !self.is_inside_local(
&self.view().transform.to_local_vec(&other_point));
}
fn view(&self) -> &Surface3Data;
}
pub type Surface3Ptr = Arc<RwLock<dyn Surface3>>;
pub trait SurfaceBuilderBase3 {
fn with_is_normal_flipped(&mut self, is_normal_flipped: bool) -> &mut Self {
self.view().is_normal_flipped = is_normal_flipped;
return self;
}
fn with_translation(&mut self, translation: Vector3D) -> &mut Self {
self.view().transform.set_translation(translation);
return self;
}
fn with_orientation(&mut self, orientation: QuaternionD) -> &mut Self {
self.view().transform.set_orientation(orientation);
return self;
}
fn with_transform(&mut self, transform: Transform3) -> &mut Self {
self.view().transform = transform;
return self;
}
fn view(&mut self) -> &mut Surface3Data;
}