use crate::surface2::*;
use crate::vector2::Vector2D;
use crate::transform2::Transform2;
use crate::bounding_box2::BoundingBox2D;
use crate::ray2::Ray2D;
use crate::plane2::Plane2;
use std::sync::{RwLock, Arc};
pub struct Box2 {
bound: BoundingBox2D,
pub surface_data: Surface2Data,
}
impl Box2 {
pub fn new_default(transform: Option<Transform2>,
is_normal_flipped: Option<bool>) -> Box2 {
return Box2 {
bound: BoundingBox2D::new(Vector2D::new_default(), Vector2D::new(1.0, 1.0)),
surface_data: Surface2Data::new(transform, is_normal_flipped),
};
}
pub fn new(lower_corner: Vector2D,
upper_corner: Vector2D,
transform: Option<Transform2>,
is_normal_flipped: Option<bool>) -> Box2 {
return Box2 {
bound: BoundingBox2D::new(lower_corner, upper_corner),
surface_data: Surface2Data::new(transform, is_normal_flipped),
};
}
pub fn new_aabb(bounding_box: BoundingBox2D,
transform: Option<Transform2>,
is_normal_flipped: Option<bool>) -> Box2 {
return Box2 {
bound: bounding_box,
surface_data: Surface2Data::new(transform, is_normal_flipped),
};
}
pub fn builder() -> Builder {
return Builder::new();
}
}
impl Surface2 for Box2 {
fn closest_point_local(&self, other_point: &Vector2D) -> Vector2D {
return if self.bound.contains(&other_point) {
let planes = [Plane2::new(Vector2D::new(1.0, 0.0), self.bound.upper_corner, None, None),
Plane2::new(Vector2D::new(0.0, 1.0), self.bound.upper_corner, None, None),
Plane2::new(Vector2D::new(-1.0, 0.0), self.bound.lower_corner, None, None),
Plane2::new(Vector2D::new(0.0, -1.0), self.bound.lower_corner, None, None)];
let mut result = planes[0].closest_point(other_point);
let mut distance_squared = result.distance_squared_to(*other_point);
for i in 1..4 {
let local_result = planes[i].closest_point(other_point);
let local_distance_squared =
local_result.distance_squared_to(*other_point);
if local_distance_squared < distance_squared {
result = local_result;
distance_squared = local_distance_squared;
}
}
result
} else {
crate::vector2::clamp(&other_point, &self.bound.lower_corner, &self.bound.upper_corner)
};
}
fn bounding_box_local(&self) -> BoundingBox2D {
return self.bound.clone();
}
fn closest_intersection_local(&self, ray: &Ray2D) -> SurfaceRayIntersection2 {
let mut intersection = SurfaceRayIntersection2::new();
let bb_ray_intersection =
self.bound.closest_intersection(&ray);
intersection.is_intersecting = bb_ray_intersection.is_intersecting;
if intersection.is_intersecting {
intersection.distance = bb_ray_intersection.t_near;
intersection.point = ray.point_at(bb_ray_intersection.t_near);
intersection.normal = self.closest_normal_local(&intersection.point);
}
return intersection;
}
fn closest_normal_local(&self, other_point: &Vector2D) -> Vector2D {
let planes = [Plane2::new(Vector2D::new(1.0, 0.0), self.bound.upper_corner, None, None),
Plane2::new(Vector2D::new(0.0, 1.0), self.bound.upper_corner, None, None),
Plane2::new(Vector2D::new(-1.0, 0.0), self.bound.lower_corner, None, None),
Plane2::new(Vector2D::new(0.0, -1.0), self.bound.lower_corner, None, None)];
return if self.bound.contains(other_point) {
let mut closest_normal = planes[0].normal;
let closest_point = planes[0].closest_point(other_point);
let mut min_distance_squared = (closest_point - *other_point).length_squared();
for i in 1..4 {
let local_closest_point = planes[i].closest_point(other_point);
let local_distance_squared =
(local_closest_point - *other_point).length_squared();
if local_distance_squared < min_distance_squared {
closest_normal = planes[i].normal;
min_distance_squared = local_distance_squared;
}
}
closest_normal
} else {
let closest_point =
crate::vector2::clamp(&other_point, &self.bound.lower_corner, &self.bound.upper_corner);
let closest_point_to_input_point = *other_point - closest_point;
let mut closest_normal = planes[0].normal;
let mut max_cosine_angle = closest_normal.dot(&closest_point_to_input_point);
for i in 1..4 {
let cosine_angle = planes[i].normal.dot(&closest_point_to_input_point);
if cosine_angle > max_cosine_angle {
closest_normal = planes[i].normal;
max_cosine_angle = cosine_angle;
}
}
closest_normal
};
}
fn intersects_local(&self, ray_local: &Ray2D) -> bool {
return self.bound.intersects(ray_local);
}
fn view(&self) -> &Surface2Data {
return &self.surface_data;
}
}
pub type Box2Ptr = Arc<RwLock<Box2>>;
pub struct Builder {
_lower_corner: Vector2D,
_upper_corner: Vector2D,
_surface_data: Surface2Data,
}
impl Builder {
pub fn with_lower_corner(&mut self, pt: Vector2D) -> &mut Self {
self._lower_corner = pt;
return self;
}
pub fn with_upper_corner(&mut self, pt: Vector2D) -> &mut Self {
self._upper_corner = pt;
return self;
}
pub fn with_bounding_box(&mut self, bbox: BoundingBox2D) -> &mut Self {
self._lower_corner = bbox.lower_corner;
self._upper_corner = bbox.upper_corner;
return self;
}
pub fn build(&mut self) -> Box2 {
return Box2::new_aabb(
BoundingBox2D::new(self._lower_corner, self._upper_corner),
Some(self._surface_data.transform.clone()),
Some(self._surface_data.is_normal_flipped),
);
}
pub fn make_shared(&mut self) -> Box2Ptr {
return Box2Ptr::new(RwLock::new(self.build()));
}
pub fn new() -> Builder {
return Builder {
_lower_corner: Vector2D::new_default(),
_upper_corner: Vector2D::new(1.0, 1.0),
_surface_data: Surface2Data::new(None, None),
};
}
}
impl SurfaceBuilderBase2 for Builder {
fn view(&mut self) -> &mut Surface2Data {
return &mut self._surface_data;
}
}