use nalgebra::{Point3, Vector3};
use crate::{Classification, Plane3D, PlaneSide};
#[derive(Debug, Clone, PartialEq)]
pub struct Triangle {
vertices: [Point3<f32>; 3],
}
impl Triangle {
pub fn new(a: Point3<f32>, b: Point3<f32>, c: Point3<f32>) -> Self {
Self {
vertices: [a, b, c],
}
}
#[inline]
pub fn vertices(&self) -> &[Point3<f32>; 3] {
&self.vertices
}
pub fn normal(&self) -> Vector3<f32> {
let [a, b, c] = &self.vertices;
let ab = b - a;
let ac = c - a;
ab.cross(&ac)
}
pub fn unit_normal(&self) -> Option<Vector3<f32>> {
let n = self.normal();
let len = n.norm();
if len > f32::EPSILON {
Some(n / len)
} else {
None
}
}
pub fn plane(&self) -> Plane3D {
let [a, b, c] = &self.vertices;
Plane3D::from_three_points(*a, *b, *c)
}
pub fn centroid(&self) -> Point3<f32> {
let [a, b, c] = &self.vertices;
Point3::from((a.coords + b.coords + c.coords) / 3.0)
}
pub fn classify(&self, plane: &Plane3D) -> Classification {
let mut front = 0;
let mut back = 0;
let mut on_plane = 0;
for vertex in &self.vertices {
match plane.classify_point(*vertex) {
PlaneSide::Front => front += 1,
PlaneSide::Back => back += 1,
PlaneSide::OnPlane => on_plane += 1,
}
}
if on_plane == 3 {
Classification::Coplanar
} else if back == 0 {
Classification::Front
} else if front == 0 {
Classification::Back
} else {
Classification::Spanning
}
}
}
impl From<Triangle> for Plane3D {
fn from(triangle: Triangle) -> Self {
triangle.plane()
}
}
impl From<&Triangle> for Plane3D {
fn from(triangle: &Triangle) -> Self {
triangle.plane()
}
}