use crate::vector2::Vector2D;
use crate::bounding_box2::BoundingBox2D;
use crate::ray2::Ray2D;
use crate::transform2::Transform2;
use std::sync::{RwLock, Arc};
pub struct SurfaceRayIntersection2 {
pub is_intersecting: bool,
pub distance: f64,
pub point: Vector2D,
pub normal: Vector2D,
}
impl SurfaceRayIntersection2 {
pub fn new() -> SurfaceRayIntersection2 {
return SurfaceRayIntersection2 {
is_intersecting: false,
distance: f64::MAX,
point: Vector2D::new_default(),
normal: Vector2D::new_default(),
};
}
}
pub struct Surface2Data {
pub transform: Transform2,
pub is_normal_flipped: bool,
}
impl Surface2Data {
pub fn new(transform: Option<Transform2>,
is_normal_flipped: Option<bool>) -> Surface2Data {
return Surface2Data {
transform: transform.unwrap_or(Transform2::new_default()),
is_normal_flipped: is_normal_flipped.unwrap_or(false),
};
}
}
pub trait Surface2 {
fn closest_point_local(&self, other_point: &Vector2D) -> Vector2D;
fn bounding_box_local(&self) -> BoundingBox2D;
fn closest_intersection_local(&self, ray: &Ray2D) -> SurfaceRayIntersection2;
fn closest_normal_local(&self, other_point: &Vector2D) -> Vector2D;
fn intersects_local(&self, ray_local: &Ray2D) -> bool {
let result = self.closest_intersection_local(ray_local);
return result.is_intersecting;
}
fn closest_distance_local(&self, other_point_local: &Vector2D) -> f64 {
return other_point_local.distance_to(self.closest_point_local(other_point_local));
}
fn is_inside_local(&self, other_point_local: &Vector2D) -> 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: &Vector2D) -> Vector2D {
return self.view().transform.to_world_vec(&self.closest_point_local(
&self.view().transform.to_local_vec(&other_point)));
}
fn bounding_box(&self) -> BoundingBox2D {
return self.view().transform.to_world_aabb(&self.bounding_box_local());
}
fn intersects(&self, ray: &Ray2D) -> bool {
return self.intersects_local(&self.view().transform.to_local_ray(&ray));
}
fn closest_distance(&self, other_point: &Vector2D) -> f64 {
return self.closest_distance_local(&self.view().transform.to_local_vec(&other_point));
}
fn closest_intersection(&self, ray: &Ray2D) -> SurfaceRayIntersection2 {
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: &Vector2D) -> Vector2D {
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: &Vector2D) -> bool {
return self.view().is_normal_flipped == !self.is_inside_local(
&self.view().transform.to_local_vec(&other_point));
}
fn view(&self) -> &Surface2Data;
}
pub type Surface2Ptr = Arc<RwLock<dyn Surface2>>;
pub trait SurfaceBuilderBase2 {
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: Vector2D) -> &mut Self {
self.view().transform.set_translation(translation);
return self;
}
fn with_orientation(&mut self, orientation: f64) -> &mut Self {
self.view().transform.set_orientation(orientation);
return self;
}
fn with_transform(&mut self, transform: Transform2) -> &mut Self {
self.view().transform = transform;
return self;
}
fn view(&mut self) -> &mut Surface2Data;
}