use crate::common::VertexIndex;
use crate::common::macros::{integrity_assert, integrity_assert_eq};
use crate::corner_table::TriangleIndex;
use crate::corner_table::common::CornerTableData;
use crate::corner_table::{CornerIndex, CornerTable, VertexFan};
impl<const ENABLE_UNSAFE: bool> CornerTable<ENABLE_UNSAFE> {
#[inline(always)]
pub(crate) fn opposite(&self, corner: CornerIndex) -> CornerIndex {
integrity_assert!(
!self.is_corner_deleted(corner),
"Corner was deleted {corner:?}"
);
let o = self.data.opposite(corner);
integrity_assert!(
!self.is_corner_deleted(o),
"Fail! Opposite corner was deleted {o:?}. Origin corner {:?}",
self.dbg_corner(corner)
);
o
}
#[inline(always)]
pub(crate) fn try_opposite(&self, corner: CornerIndex) -> Option<CornerIndex> {
integrity_assert!(
!self.is_corner_deleted(corner),
"Corner was deleted {corner:?}"
);
let o = self.data.opposite(corner);
if o.is_valid() { Some(o) } else { None }
}
#[inline(always)]
pub(crate) fn set_dual_opposite(&mut self, ca: CornerIndex, cb: CornerIndex) {
integrity_assert!(
!self.is_corner_deleted(ca),
"triangle {} was deleted",
self.data.dbg_corner(ca)
);
integrity_assert!(
!self.is_corner_deleted(cb),
"triangle {} was deleted",
self.data.dbg_corner(cb)
);
self.data.set_dual_opposite(ca, cb)
}
#[inline(always)]
pub(crate) fn clear_opposite(&mut self, ca: CornerIndex) {
integrity_assert!(
!self.is_corner_deleted(ca),
"triangle {} was deleted",
self.data.dbg_corner(ca)
);
self.data.set_opposite(ca, CornerIndex::INVALID)
}
#[inline(always)]
pub(crate) fn corner(&self, vertex: VertexIndex) -> CornerIndex {
integrity_assert!(vertex.is_valid());
if ENABLE_UNSAFE {
unsafe {
*self
.data
.corner_of_vertex_vec
.get_unchecked(vertex.0 as usize)
}
} else {
self.data.corner_of_vertex_vec[vertex.0 as usize]
}
}
#[inline(always)]
pub(crate) fn vertex(&self, corner: CornerIndex) -> VertexIndex {
integrity_assert!(corner.is_valid());
integrity_assert!(
!self.is_corner_deleted(corner),
"Corner {corner:?} was deleted"
);
integrity_assert!(
self.data.vertex_of_corner(corner).is_valid(),
"Valid corner had no vertex:{}",
self.data.dbg_corner(corner)
);
self.data.vertex_of_corner(corner)
}
#[inline(always)]
pub(crate) fn swing_ccw(&self, corner: CornerIndex) -> CornerIndex {
self.next(self.opposite(self.next(corner)))
}
#[inline(always)]
pub(crate) fn try_swing_ccw(&self, corner: CornerIndex) -> Option<CornerIndex> {
self.try_opposite(self.next(corner)).map(|o| self.next(o))
}
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn swing_cw(&self, corner: CornerIndex) -> CornerIndex {
self.prev(self.opposite(self.prev(corner)))
}
#[inline(always)]
pub(crate) fn try_swing_cw(&self, corner: CornerIndex) -> Option<CornerIndex> {
self.try_opposite(self.prev(corner)).map(|c| c.prev())
}
#[inline(always)]
#[allow(clippy::let_and_return)]
pub(crate) fn twin(&self, corner: CornerIndex) -> CornerIndex {
let t = self.next(self.opposite(self.prev(corner)));
integrity_assert!(t.is_valid());
integrity_assert_eq!(
self.vertex(t),
self.vertex(self.next(corner)),
"V(corner.next:{}) != V(corner.twin:{})",
self.dbg_corner(corner.next()),
self.dbg_corner(t),
);
t
}
#[inline(always)]
pub(crate) fn next(&self, corner: CornerIndex) -> CornerIndex {
integrity_assert!(!self.is_corner_deleted(corner));
corner.next()
}
#[inline(always)]
pub(crate) fn prev(&self, corner: CornerIndex) -> CornerIndex {
integrity_assert!(!self.is_corner_deleted(corner));
corner.prev()
}
#[inline(always)]
pub(crate) fn next_prev(&self, corner: CornerIndex) -> (CornerIndex, CornerIndex) {
integrity_assert!(!self.is_corner_deleted(corner));
corner.next_prev()
}
pub(crate) fn ccw_vertex_fan(&self, start_corner: CornerIndex) -> VertexFan {
integrity_assert!(start_corner.is_valid());
integrity_assert!(self.triangle_pool.is_used(start_corner.into()));
let mut vertex_fan = VertexFan::with_capacity(super::DEFAULT_MAX_VALENCE as usize + 2);
integrity_assert!(start_corner.is_valid());
let mut current_corner = start_corner;
loop {
vertex_fan.push(current_corner);
let next_corner = self.swing_ccw(current_corner);
integrity_assert!(next_corner.is_valid());
if next_corner == start_corner || !next_corner.is_valid() {
break;
}
current_corner = next_corner;
}
if cfg!(feature = "integrity_check") {
let v0 = self.vertex(start_corner);
let mut iter = vertex_fan.iter();
assert_eq!(start_corner, *iter.next().unwrap());
for &_c in iter {
assert_eq!(v0, self.vertex(_c));
}
}
vertex_fan
}
pub(crate) fn find_swing_avoiding_triangles(
&self,
start: CornerIndex,
avoid: &[TriangleIndex],
) -> CornerIndex {
let mut current = self.swing_ccw(start);
let first = current;
loop {
if !avoid.contains(¤t.triangle()) {
return current;
}
current = self.swing_ccw(current);
if current == first {
return CornerIndex::INVALID; }
}
}
pub(crate) fn valence(&self, start_corner: CornerIndex) -> i16 {
integrity_assert!(start_corner.is_valid());
let mut current_corner = start_corner;
let mut valence = 1;
loop {
let next_corner = self.swing_ccw(current_corner);
if next_corner == start_corner {
break; }
valence += 1;
current_corner = next_corner;
}
integrity_assert!(valence > 2);
valence
}
#[inline(always)]
pub(crate) fn link_corner_vertex(&mut self, corner: CornerIndex, vertex: VertexIndex) {
self.set_corner_of_vertex(vertex, corner);
self.set_vertex_of_corner(corner, vertex);
}
#[inline(always)]
pub(crate) fn set_corner_of_vertex(&mut self, vertex: VertexIndex, corner: CornerIndex) {
integrity_assert!(vertex.is_valid());
integrity_assert!(corner.is_valid());
integrity_assert!(!self.is_corner_deleted(corner));
if ENABLE_UNSAFE {
unsafe {
*self
.data
.corner_of_vertex_vec
.get_unchecked_mut(vertex.usize()) = corner;
}
} else {
self.data.corner_of_vertex_vec[vertex.usize()] = corner;
}
}
#[inline(always)]
pub(crate) fn set_vertex_of_corner(&mut self, corner: CornerIndex, vertex: VertexIndex) {
integrity_assert!(vertex.is_valid());
integrity_assert!(corner.is_valid());
integrity_assert!(!self.is_corner_deleted(corner));
if ENABLE_UNSAFE {
unsafe {
*self
.data
.vertex_of_corner_vec
.get_unchecked_mut(corner.usize()) = vertex;
}
} else {
self.data.vertex_of_corner_vec[corner.usize()] = vertex;
}
}
}
impl<const ENABLE_UNSAFE: bool> CornerTableData<ENABLE_UNSAFE> {
#[inline(always)]
pub(super) fn set_dual_opposite(&mut self, ca: CornerIndex, cb: CornerIndex) {
self.set_opposite(ca, cb);
self.set_opposite(cb, ca);
}
#[inline(always)]
pub(super) fn set_opposite(&mut self, ca: CornerIndex, cb: CornerIndex) {
if ENABLE_UNSAFE {
unsafe {
*self.opposite_corner_vec.get_unchecked_mut(ca.usize()) = cb;
}
} else {
self.opposite_corner_vec[ca.usize()] = cb;
}
}
#[inline(always)]
pub(super) fn opposite(&self, corner: CornerIndex) -> CornerIndex {
if ENABLE_UNSAFE {
unsafe { *self.opposite_corner_vec.get_unchecked(corner.0 as usize) }
} else {
self.opposite_corner_vec[corner.0 as usize]
}
}
#[inline(always)]
pub(super) fn vertex_of_corner(&self, corner: CornerIndex) -> VertexIndex {
if ENABLE_UNSAFE {
unsafe { *self.vertex_of_corner_vec.get_unchecked(corner.0 as usize) }
} else {
self.vertex_of_corner_vec[corner.0 as usize]
}
}
}