use crate::common::VertexIndex;
use crate::common::macros::{
integrity_assert, integrity_assert_eq, integrity_assert_ne, integrity_println,
};
use crate::corner_table::common::CornerTableData;
use crate::corner_table::{CornerIndex, CornerTable, TriangleIndex};
use crate::util::index_pool::Allocation;
impl<const ENABLE_UNSAFE: bool> CornerTable<ENABLE_UNSAFE> {
pub(crate) fn free_two_adjacent_triangles(&mut self, t0: TriangleIndex, t1: TriangleIndex) {
integrity_assert!(!self.is_triangle_deleted(t0));
integrity_assert!(!self.is_triangle_deleted(t1));
let corners0 = t0.corners();
let corners1 = t1.corners();
let vertices0 = corners0.map(|c| self.data.vertex_of_corner(c));
let vertices1 = corners1.map(|c| self.data.vertex_of_corner(c));
let mut vertex_swings = [(VertexIndex::INVALID, CornerIndex::INVALID); 4];
let mut count = 0;
for (&corner, &vertex) in corners0
.iter()
.chain(&corners1)
.zip(vertices0.iter().chain(&vertices1))
{
if vertex_swings[..count].iter().any(|(v, _)| *v == vertex) {
continue;
}
integrity_assert!(
count < 4,
"More than 4 unique vertices found for two triangles"
);
let swing = self.find_swing_avoiding_triangles(corner, &[t0, t1]);
integrity_assert!(swing.is_valid());
vertex_swings[count] = (vertex, swing);
count += 1;
if cfg!(not(any(feature = "integrity_check", debug_assertions))) && count == 4 {
break;
}
}
for &(vertex, swing) in &vertex_swings[..count] {
self.data.set_default_corner_of_vertex(vertex, swing);
}
self.free_triangle_some_cleanup(t0);
self.free_triangle_some_cleanup(t1);
}
pub(crate) fn free_triangle_some_cleanup(&mut self, t: TriangleIndex) {
integrity_assert!(!self.is_triangle_deleted(t));
for c in t.corners() {
self.data.vertex_of_corner_vec[c.0 as usize] = VertexIndex::INVALID;
self.data.opposite_corner_vec[c.0 as usize] = CornerIndex::INVALID;
}
self.triangle_pool.push(t);
integrity_assert!(self.is_triangle_deleted(t));
}
pub(crate) fn allocate_triangle(
&mut self,
va: VertexIndex,
vb: VertexIndex,
vc: VertexIndex,
) -> (CornerIndex, CornerIndex, CornerIndex) {
#[cfg(feature = "integrity_check")]
let _ = self.len();
match self.triangle_pool.pop() {
Allocation::Reused(t) => {
let ca = CornerIndex(t.0 * 3);
let cb = CornerIndex(ca.0 + 1);
let cc = CornerIndex(cb.0 + 1);
debug_assert!(
cc.0 < self.data.vertex_of_corner_vec.len() as u32,
"cc:{} >= vertex_of_corner.len():{}",
cc.0,
self.data.corner_of_vertex_vec.len() as u32
);
self.data.vertex_of_corner_vec[ca.0 as usize] = va;
self.data.vertex_of_corner_vec[cb.0 as usize] = vb;
self.data.vertex_of_corner_vec[cc.0 as usize] = vc;
self.data.corner_of_vertex_vec[va.0 as usize] = ca;
self.data.corner_of_vertex_vec[vb.0 as usize] = cb;
self.data.corner_of_vertex_vec[vc.0 as usize] = cc;
self.data.opposite_corner_vec[ca.0 as usize] = CornerIndex::INVALID;
self.data.opposite_corner_vec[cb.0 as usize] = CornerIndex::INVALID;
self.data.opposite_corner_vec[cb.0 as usize] = CornerIndex::INVALID;
integrity_println!(
"reused triangle: ca:{},cb:{},cc:{} populated with invalid opposites",
self.data.dbg_corner(ca),
self.data.dbg_corner(cb),
self.data.dbg_corner(cc),
);
(ca, cb, cc)
}
Allocation::New(t) => {
integrity_assert_eq!(
self.data.vertex_of_corner_vec.len(),
self.data.opposite_corner_vec.len()
);
let ca = CornerIndex(t.0 * 3);
let cb = CornerIndex(ca.0 + 1);
let cc = CornerIndex(cb.0 + 1);
debug_assert_eq!(ca.0, self.data.vertex_of_corner_vec.len() as u32);
self.data.vertex_of_corner_vec.push(va);
debug_assert_eq!(cb.0, self.data.vertex_of_corner_vec.len() as u32);
self.data.vertex_of_corner_vec.push(vb);
debug_assert_eq!(cc.0, self.data.vertex_of_corner_vec.len() as u32);
self.data.vertex_of_corner_vec.push(vc);
let maxv = VertexIndex(va.0.max(vb.0).max(vc.0));
debug_assert!(maxv.0 <= self.data.corner_of_vertex_vec.len() as u32);
if maxv.0 == self.data.corner_of_vertex_vec.len() as u32 {
self.data.corner_of_vertex_vec.push(CornerIndex::INVALID)
}
self.data.corner_of_vertex_vec[va.0 as usize] = ca;
self.data.corner_of_vertex_vec[vb.0 as usize] = cb;
self.data.corner_of_vertex_vec[vc.0 as usize] = cc;
self.data.opposite_corner_vec.push(CornerIndex::INVALID);
self.data.opposite_corner_vec.push(CornerIndex::INVALID);
self.data.opposite_corner_vec.push(CornerIndex::INVALID);
(ca, cb, cc)
}
}
}
pub(crate) fn defragment_triangles(&mut self) {
let old_size = self.triangle_pool.active_count();
self.triangle_pool.defragment(|from_idx, to_idx| {
self.data.remap_triangle_references(from_idx, to_idx);
});
self.data
.vertex_of_corner_vec
.truncate((old_size * 3) as usize);
self.data
.opposite_corner_vec
.truncate((old_size * 3) as usize);
}
#[inline(always)]
pub(crate) fn delete_vertex(&mut self, vertex: VertexIndex) {
debug_assert!(vertex.is_valid());
self.data.corner_of_vertex_vec[vertex.0 as usize] = CornerIndex::INVALID;
integrity_println!("Deleting vertex {vertex:?}");
}
#[inline(always)]
pub(crate) fn handle_new_vertex(&mut self, vertex: VertexIndex) {
#[cfg(feature = "integrity_check")]
let _ = self.len();
debug_assert!(vertex.is_valid());
debug_assert_eq!(vertex.0, self.data.corner_of_vertex_vec.len() as u32);
self.data.corner_of_vertex_vec.push(CornerIndex::INVALID);
#[cfg(feature = "integrity_check")]
let _ = self.len();
}
#[inline(always)]
pub(crate) fn handle_reused_vertex(&mut self, vertex: VertexIndex) {
#[cfg(feature = "integrity_check")]
let _ = self.len();
debug_assert!(vertex.is_valid());
debug_assert!(vertex.0 < self.data.corner_of_vertex_vec.len() as u32);
integrity_println!("Resused vertex {vertex:?}");
#[cfg(feature = "integrity_check")]
let _ = self.len();
}
}
impl<const ENABLE_UNSAFE: bool> CornerTableData<ENABLE_UNSAFE> {
fn remap_triangle_references(&mut self, old_idx: TriangleIndex, new_idx: TriangleIndex) {
integrity_assert_ne!(old_idx, new_idx);
let new_base = new_idx.0 * 3;
let old_base = old_idx.0 * 3;
integrity_println!(
"moving triangle {old_idx:?}: {} {} {}",
self.dbg_corner(CornerIndex(old_base + 0)),
self.dbg_corner(CornerIndex(old_base + 1)),
self.dbg_corner(CornerIndex(old_base + 2))
);
for i in 0..3 {
self.vertex_of_corner_vec[(new_base + i) as usize] =
self.vertex_of_corner_vec[(old_base + i) as usize];
self.set_dual_opposite(
CornerIndex(new_base + i),
self.opposite_corner_vec[(old_base + i) as usize],
);
self.set_default_corner_of_vertex(
self.vertex_of_corner_vec[(new_base + i) as usize],
CornerIndex(new_base + i),
);
}
integrity_println!(
"to triangle {new_idx:?}: {} {} {}",
self.dbg_corner(CornerIndex(new_base + 0)),
self.dbg_corner(CornerIndex(new_base + 1)),
self.dbg_corner(CornerIndex(new_base + 2))
);
}
}