use crate::common::VertexIndex;
use crate::common::macros::{integrity_assert, integrity_assert_eq};
use crate::corner_table::CornerIndex;
use crate::corner_table::triangle_index::TriangleIndex;
use crate::util::index_pool::LifoPool;
use smallvec::SmallVec;
pub(crate) const DEFAULT_MAX_VALENCE: i16 = 8;
#[derive(Clone)]
pub(crate) struct CornerTableData<const ENABLE_UNSAFE: bool> {
pub(super) vertex_of_corner_vec: Vec<VertexIndex>,
pub(super) opposite_corner_vec: Vec<CornerIndex>,
pub(super) corner_of_vertex_vec: Vec<CornerIndex>,
}
#[derive(Clone)]
pub(crate) struct CornerTable<const ENABLE_UNSAFE: bool> {
pub(crate) data: CornerTableData<ENABLE_UNSAFE>,
pub(crate) triangle_pool: LifoPool<TriangleIndex, ENABLE_UNSAFE>,
}
pub(crate) type VertexFan = SmallVec<[CornerIndex; 7]>;
impl<const ENABLE_UNSAFE: bool> CornerTable<ENABLE_UNSAFE> {
pub(crate) fn new(
vertex_of_corner: Vec<VertexIndex>,
opposite_corner: Vec<CornerIndex>,
corner_of_vertex: Vec<CornerIndex>,
) -> Self {
let num_corners = vertex_of_corner.len() as u32;
debug_assert_eq!(num_corners, opposite_corner.len() as u32);
let triangle_pool = LifoPool::<TriangleIndex, ENABLE_UNSAFE>::new(num_corners / 3);
debug_assert_eq!(num_corners / 3, triangle_pool.total_count());
Self {
data: CornerTableData {
vertex_of_corner_vec: vertex_of_corner,
opposite_corner_vec: opposite_corner,
corner_of_vertex_vec: corner_of_vertex,
},
triangle_pool,
}
}
#[inline(always)]
pub(crate) fn vertex_of_corners(&self) -> &[VertexIndex] {
&self.data.vertex_of_corner_vec
}
#[inline(always)]
pub(crate) fn canonical_edge(&self, corner: CornerIndex) -> (VertexIndex, VertexIndex) {
let vc = self.vertex(corner);
let vc_next = self.vertex(self.next(corner));
VertexIndex::canonical_pair(vc, vc_next)
}
#[inline(always)]
pub(crate) fn canonical_edge_hash(&self, corner: CornerIndex) -> u64 {
use std::hash::{DefaultHasher, Hash, Hasher};
let mut hasher = DefaultHasher::new();
self.canonical_edge(corner).hash(&mut hasher);
hasher.finish()
}
#[inline(always)]
pub fn is_triangle_deleted(&self, t: TriangleIndex) -> bool {
!t.is_valid()
|| if cfg!(any(feature = "integrity_check", debug_assertions)) {
assert!(t.0 < self.triangle_pool.total_count());
let fast_method =
!self.data.vertex_of_corner_vec[t.base_corner().0 as usize].is_valid();
let slow_method = !self.triangle_pool.is_used(t);
assert_eq!(fast_method, slow_method);
fast_method
} else {
!if ENABLE_UNSAFE {
unsafe {
*self
.data
.vertex_of_corner_vec
.get_unchecked(t.base_corner().0 as usize)
}
} else {
self.data.vertex_of_corner_vec[t.base_corner().0 as usize]
}
.is_valid()
}
}
#[inline(always)]
pub fn is_corner_deleted(&self, c: CornerIndex) -> bool {
!c.is_valid()
|| if cfg!(any(feature = "integrity_check", debug_assertions)) {
let fast_method = !self.data.vertex_of_corner_vec[c.0 as usize].is_valid();
let slow_method = !self.triangle_pool.is_used(c.triangle());
assert_eq!(fast_method, slow_method);
fast_method
} else {
!if ENABLE_UNSAFE {
unsafe { *self.data.vertex_of_corner_vec.get_unchecked(c.0 as usize) }
} else {
self.data.vertex_of_corner_vec[c.0 as usize]
}
.is_valid()
}
}
#[inline(always)]
pub(crate) fn deleted_triangle_count(&self) -> u32 {
self.triangle_pool.available_count()
}
#[inline(always)]
pub(crate) fn total_triangle_count(&self) -> u32 {
integrity_assert_eq!(
self.data.vertex_of_corner_vec.len(),
self.data.opposite_corner_vec.len()
);
integrity_assert_eq!(
self.triangle_pool.total_count(),
self.data.vertex_of_corner_vec.len() as u32 / 3
);
self.triangle_pool.total_count()
}
#[inline(always)]
pub(crate) fn active_triangles(&self) -> u32 {
self.triangle_pool.active_count()
}
pub(crate) fn take_triangles(self) -> Vec<u32> {
bytemuck::cast_vec::<VertexIndex, u32>(self.data.vertex_of_corner_vec)
}
pub(super) fn clone_vertex<T: Clone>(
&mut self,
vertices: &mut Vec<T>,
source_vertex: VertexIndex,
) -> VertexIndex {
integrity_assert_eq!(vertices.len(), self.data.corner_of_vertex_vec.len());
let new_vertex_idx = VertexIndex(vertices.len() as u32);
vertices.push(vertices[source_vertex.usize()].clone());
self.data.corner_of_vertex_vec.push(CornerIndex::INVALID);
integrity_assert_eq!(vertices.len(), self.data.corner_of_vertex_vec.len());
new_vertex_idx
}
pub(crate) fn dbg_corner(&self, c: CornerIndex) -> String {
self.data.dbg_corner(c)
}
pub(crate) fn dbg_corners(&self, corners: &[CornerIndex]) -> String {
corners
.iter()
.map(|c| self.dbg_corner(*c))
.collect::<Vec<_>>()
.join(",")
}
}
impl<const ENABLE_UNSAFE: bool> CornerTableData<ENABLE_UNSAFE> {
#[inline(always)]
pub(crate) fn set_default_corner_of_vertex(
&mut self,
vertex: VertexIndex,
corner: CornerIndex,
) {
integrity_assert!(corner.is_valid());
integrity_assert!(vertex.is_valid());
if ENABLE_UNSAFE {
unsafe {
*self
.corner_of_vertex_vec
.get_unchecked_mut(vertex.0 as usize) = corner;
}
} else {
self.corner_of_vertex_vec[vertex.0 as usize] = corner;
}
}
pub(crate) fn dbg_corner(&self, c: CornerIndex) -> String {
let o = self.opposite(c);
let o = if o.is_valid() {
format!("{}", o.0)
} else {
"∅".to_string()
};
format!("{c:?}O{}{:?}", o, self.vertex_of_corner(c))
}
}