use std::cmp::Ordering;
use glam_det::{Cross, Dot, Point3, UnitVec3, Vec3};
use smallvec::SmallVec;
use vslab::{new_type_id, Slab};
use crate::common::normalize_and_len;
use crate::half_edge::{EdgeMap, HalfEdge, HalfEdgeKey};
use crate::quick_hull_3d::MAX_POINT_COUNT;
new_type_id!(FaceKey);
pub(crate) type FaceMap = Slab<FaceKey, Face>;
pub(crate) type FaceIndexSmallVec = SmallVec<[FaceKey; 16]>;
pub(crate) type ConflictPointIndexSmallVec = SmallVec<[usize; 16]>;
pub struct Face {
pub edge_index: HalfEdgeKey,
pub normal: UnitVec3,
pub center: Point3,
pub area: f32,
pub(crate) visited: bool,
pub(crate) conflict_points: ConflictPointIndexSmallVec,
pub(crate) mark: FaceState,
pub num_points: u32,
pub max_distance_for_expand: f32,
#[cfg(any(test, feature = "safe_check", feature = "dump"))]
pub vertex: Vec<usize>,
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum FaceState {
Visible,
NonConvex,
Delete,
}
impl Face {
#[inline]
pub(crate) fn new(
edge_index: HalfEdgeKey,
center: Point3,
normal: UnitVec3,
area: f32,
num_points: u32,
) -> Self {
Self {
edge_index,
normal,
center,
area,
visited: false,
conflict_points: ConflictPointIndexSmallVec::default(),
mark: FaceState::Visible,
num_points,
max_distance_for_expand: 0.0,
#[cfg(any(test, feature = "safe_check", feature = "dump"))]
vertex: vec![],
}
}
pub(crate) fn update_normal_and_center(&mut self, edges: &EdgeMap, points: &[Point3]) {
if self.mark == FaceState::Delete {
return;
}
#[cfg(any(test, feature = "safe_check", feature = "dump"))]
self.vertex.clear();
let edge_iter = &mut FaceEdgeIter::new(self.edge_index, edges);
let mut normal = Vec3::ZERO;
let mut center = Vec3::ZERO;
let mut count = 0_u32;
let mut first_iter = edge_iter.take(1);
let (_, first_edge) = first_iter
.next()
.expect("the face has no edge,it should not happen");
let a = points[first_edge.origin];
center += a.as_vec3();
count += 1;
#[cfg(any(test, feature = "safe_check", feature = "dump"))]
self.vertex.push(first_edge.origin);
let mut last_vector = points[first_edge.destination] - a;
for (_, edge) in edge_iter {
#[cfg(any(test, feature = "safe_check", feature = "dump"))]
self.vertex.push(edge.origin);
let b = points[edge.destination];
let this_vector = b - a;
let cross = this_vector.cross(last_vector);
normal += cross;
center += points[edge.origin].as_vec3();
count += 1;
debug_assert!(count < MAX_POINT_COUNT, "face point count overflow");
last_vector = this_vector;
}
(self.normal, self.area) = normalize_and_len(normal, 0.0);
self.num_points = count;
self.center = Point3::from_vec3(center / count as f32);
}
pub fn get_face_triangles(&self, edges: &EdgeMap, triangles: &mut Vec<usize>) {
let mut iter = FaceEdgeIter::new(self.edge_index, edges);
let first_point = iter.next().expect("the face has no edge").1.origin;
let mut prev = iter.next().expect("the face has only one edge");
for current in iter {
let edge = prev.1;
triangles.push(first_point);
triangles.push(edge.destination);
triangles.push(edge.origin);
prev = current;
}
}
#[cfg(feature = "safe_check")]
#[inline]
pub(crate) fn first_vertex_index(&self, edges: &EdgeMap) -> usize {
edges[self.edge_index].origin
}
#[inline]
pub(crate) fn distance(&self, point: Point3) -> f32 {
let self_point = self.center;
let offset = point - self_point;
offset.dot(self.normal)
}
#[inline]
pub(crate) fn remove_conflict_point(&mut self, point_index: usize) {
self.conflict_points.retain(|&mut x| x != point_index);
}
#[inline]
pub(crate) fn get_max_distance_conflict_index(&self, points: &[Point3]) -> Option<&usize> {
self.conflict_points.iter().max_by(|&&x, &&y| {
let distance_x = self.distance(points[x]);
let distance_y = self.distance(points[y]);
if distance_x > distance_y {
Ordering::Greater
} else {
Ordering::Less
}
})
}
}
pub struct FaceEdgeIterInv<'a> {
init_edge_index: HalfEdgeKey,
edges: &'a EdgeMap,
now_edge_index: HalfEdgeKey,
end: bool,
}
pub struct FaceEdgeIter<'a> {
init_edge_index: HalfEdgeKey,
edges: &'a EdgeMap,
now_edge_index: HalfEdgeKey,
end: bool,
}
impl<'a> FaceEdgeIter<'a> {
#[inline]
#[must_use]
pub fn new(init_edge_index: HalfEdgeKey, edges: &'a EdgeMap) -> Self {
Self {
init_edge_index,
edges,
now_edge_index: init_edge_index,
end: false,
}
}
}
impl<'a> Iterator for FaceEdgeIter<'a> {
type Item = (HalfEdgeKey, &'a HalfEdge);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.end {
return None;
}
let key = self.now_edge_index;
let edge = &self.edges[key];
self.now_edge_index = edge.next();
self.end = self.now_edge_index == self.init_edge_index;
Some((key, edge))
}
}
impl<'a> FaceEdgeIterInv<'a> {
#[inline]
#[must_use]
pub fn new(init_edge_index: HalfEdgeKey, edges: &'a EdgeMap) -> Self {
Self {
init_edge_index,
edges,
now_edge_index: init_edge_index,
end: false,
}
}
}
impl<'a> Iterator for FaceEdgeIterInv<'a> {
type Item = (HalfEdgeKey, &'a HalfEdge);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.end {
return None;
}
let key = self.now_edge_index;
let edge = &self.edges[key];
self.now_edge_index = edge.prev();
self.end = self.now_edge_index == self.init_edge_index;
Some((key, edge))
}
}