use vector3::Vector3;
use crate::base::{Shape, Intersection};
use crate::plane::Plane;
use crate::line3::Line3;
use list::List;
#[derive(Clone, Copy)]
pub struct Triangle3 {
pub a: Vector3, pub b: Vector3, pub c: Vector3,
pub plane: Plane,
ab: Vector3, ac: Vector3,
d00: f64,
d01: f64,
d11: f64,
denom: f64,
}
impl Triangle3 {
pub fn new(a: &Vector3, b: &Vector3, c: &Vector3) -> Triangle3 {
let ab: Vector3 = *b - *a;
let ac: Vector3 = *c - *a;
let n: Vector3 = ab.cross(&ac).normalize();
let plane: Plane = Plane::new(&a, &n);
let d00: f64 = ab.dot(&ab);
let d01: f64 = ab.dot(&ac);
let d11: f64 = ac.dot(&ac);
let denom: f64 = d00 * d11 - d01 * d01;
if denom == 0. {
panic!("The triangle cannot be defined by three aligned points.");
}
Self { a: *a, b: *b, c: *c, plane, ab, ac, d00, d01, d11, denom }
}
pub fn barycentric(&self, p: &Vector3) -> Vector3 {
let ap: Vector3 = *p - self.a;
let d20: f64 = ap.dot(&self.ab);
let d21: f64 = ap.dot(&self.ac);
let bar_b: f64 = (self.d11 * d20 - self.d01 * d21) / self.denom;
let bar_c: f64 = (self.d00 * d21 - self.d01 * d20) / self.denom;
let bar_a: f64 = 1.0 - bar_b - bar_c;
Vector3{x: bar_a, y: bar_b, z: bar_c }
}
}
impl Shape for Triangle3 {
fn normal(&self, _point: &Vector3) -> Vector3 {
self.plane.n
}
fn intersects(&self, line: &Line3) -> List::<f64> {
let intersections: List<f64> = self.plane.intersects(line);
if intersections.iter().count() == 0 {
return intersections;
}
else {
let p: Vector3 = line.calc_point(*intersections.iter().next().unwrap());
let b: Vector3 = self.barycentric(&p);
if 1.0 >= b.x && b.x >= 0.0 &&
1.0 >= b.y && b.y >= 0.0 &&
1.0 >= b.z && b.z >= 0.0 {
return intersections;
}
else {
return List::<f64>::new();
}
}
}
fn closest_intersection(&self, line: &Line3) -> Option<Intersection> {
let intersection: Option<Intersection> = self.plane.closest_intersection(line);
if intersection.is_none() {
return None;
}
else {
let p: Vector3 = line.calc_point(intersection.unwrap().lambda);
let bar: Vector3 = self.barycentric(&p);
if 1.0 >= bar.x && bar.x >= 0.0 &&
1.0 >= bar.y && bar.y >= 0.0 &&
1.0 >= bar.z && bar.z >= 0.0 {
return Some(Intersection { lambda: intersection.unwrap().lambda, barycentric: Some(bar) });
}
else {
return None;
}
}
}
}