use crate::surface3::*;
use crate::vector3::Vector3D;
use crate::transform3::Transform3;
use crate::bounding_box3::BoundingBox3D;
use crate::ray3::Ray3D;
use std::sync::{RwLock, Arc};
pub struct Plane3 {
pub normal: Vector3D,
pub point: Vector3D,
pub surface_data: Surface3Data,
}
impl Plane3 {
pub fn new_default(transform: Option<Transform3>,
is_normal_flipped: Option<bool>) -> Plane3 {
return Plane3 {
normal: Vector3D::new(0.0, 1.0, 0.0),
point: Vector3D::new_default(),
surface_data: Surface3Data::new(transform, is_normal_flipped),
};
}
pub fn new(normal: Vector3D,
point: Vector3D,
transform: Option<Transform3>,
is_normal_flipped: Option<bool>) -> Plane3 {
return Plane3 {
normal,
point,
surface_data: Surface3Data::new(transform, is_normal_flipped),
};
}
pub fn builder() -> Builder {
return Builder::new();
}
}
impl Surface3 for Plane3 {
fn closest_point_local(&self, other_point: &Vector3D) -> Vector3D {
let r = *other_point - self.point;
return r - self.normal * self.normal.dot(&r) + self.point;
}
fn bounding_box_local(&self) -> BoundingBox3D {
let eps = f64::EPSILON;
let dmax = f64::MAX;
return if f64::abs(self.normal.dot(&Vector3D::new(1.0, 0.0, 0.0)) - 1.0) < eps {
BoundingBox3D::new(self.point - Vector3D::new(0.0, dmax, dmax),
self.point + Vector3D::new(0.0, dmax, dmax))
} else if f64::abs(self.normal.dot(&Vector3D::new(0.0, 1.0, 0.0)) - 1.0) < eps {
BoundingBox3D::new(self.point - Vector3D::new(dmax, 0.0, dmax),
self.point + Vector3D::new(dmax, 0.0, dmax))
} else if f64::abs(self.normal.dot(&Vector3D::new(0.0, 0.0, 1.0)) - 1.0) < eps {
BoundingBox3D::new(self.point - Vector3D::new(dmax, dmax, 0.0),
self.point + Vector3D::new(dmax, dmax, 0.0))
} else {
BoundingBox3D::new(Vector3D::new(dmax, dmax, dmax),
Vector3D::new(dmax, dmax, dmax))
};
}
fn closest_intersection_local(&self, ray: &Ray3D) -> SurfaceRayIntersection3 {
let mut intersection = SurfaceRayIntersection3::new();
let d_dot_n = ray.direction.dot(&self.normal);
if f64::abs(d_dot_n) > 0.0 {
let t = self.normal.dot(&(self.point - ray.origin)) / d_dot_n;
if t >= 0.0 {
intersection.is_intersecting = true;
intersection.distance = t;
intersection.point = ray.point_at(t);
intersection.normal = self.normal;
}
}
return intersection;
}
fn closest_normal_local(&self, _other_point: &Vector3D) -> Vector3D {
return self.normal;
}
fn intersects_local(&self, ray_local: &Ray3D) -> bool {
return f64::abs(ray_local.direction.dot(&self.normal)) > 0.0;
}
fn view(&self) -> &Surface3Data {
return &self.surface_data;
}
}
pub type Plane3Ptr = Arc<RwLock<Plane3>>;
pub struct Builder {
_normal: Vector3D,
_point: Vector3D,
_surface_data: Surface3Data,
}
impl Builder {
pub fn with_normal(&mut self, normal: Vector3D) -> &mut Self {
self._normal = normal;
return self;
}
pub fn with_point(&mut self, point: Vector3D) -> &mut Self {
self._point = point;
return self;
}
pub fn build(&mut self) -> Plane3 {
return Plane3::new(self._normal,
self._point,
Some(self._surface_data.transform.clone()),
Some(self._surface_data.is_normal_flipped),
);
}
pub fn make_shared(&mut self) -> Plane3Ptr {
return Plane3Ptr::new(RwLock::new(self.build()));
}
pub fn new() -> Builder {
return Builder {
_normal: Vector3D::new(0.0, 1.0, 0.0),
_point: Vector3D::new_default(),
_surface_data: Surface3Data::new(None, None),
};
}
}
impl SurfaceBuilderBase3 for Builder {
fn view(&mut self) -> &mut Surface3Data {
return &mut self._surface_data;
}
}