use linear_isomorphic::InnerSpace;
use crate::data_container::StorageBuffer;
use crate::prelude::{
edge_handle::EdgeHandle,
face_handle::FaceHandle,
half_edge_handle::HalfEdgeHandle,
half_edge_handle::OrbitHalfEdgeIterator,
};
use crate::{EdgeId, HalfEdgeId, MeshData, MeshStorage, TopoVert, VertData, VertId};
pub struct VertHandle<C: MeshStorage, const MANIFOLD: bool>
{
pub(crate) mesh_data: *mut MeshData<C, MANIFOLD>,
pub(crate) id: VertId,
}
impl<C: MeshStorage, const MANIFOLD: bool> VertHandle<C, MANIFOLD>
{
pub(crate) fn new(mesh_data: *mut MeshData<C, MANIFOLD>, id: VertId) -> Self
{
Self { mesh_data, id }
}
pub fn id(&self) -> VertId { self.id }
pub fn is_isolated(&self) -> bool
{
unsafe { (*self.mesh_data).vert_ref(self.id).arc.is_void() }
}
pub fn read_data(&self) -> &VertData<C>
{
unsafe {
(*self.mesh_data)
.geometry_data
.vert_data
.read(self.id.to_index() as u64)
}
}
pub fn update_data<F: FnMut(&mut VertData<C>)>(&mut self, update: F)
{
unsafe {
(*self.mesh_data)
.geometry_data
.vert_data
.update(self.id.to_index() as u64, update)
}
}
pub fn edge(&self) -> EdgeHandle<C, MANIFOLD>
{
assert!(
!MANIFOLD,
"Cannot call `edge()` on a manifold vertex handle."
);
unsafe {
let edge_id = (*self.mesh_data).vert_ref(self.id).arc.to_edge_id();
EdgeHandle {
mesh_data: self.mesh_data,
id: edge_id,
}
}
}
pub fn has_edge(&self) -> bool
{
unsafe {
if MANIFOLD
{
!(*self.mesh_data)
.vert_ref(self.id)
.arc
.to_half_edge_id()
.is_void()
}
else
{
!(*self.mesh_data)
.vert_ref(self.id)
.arc
.to_edge_id()
.is_void()
}
}
}
pub fn half_edge(&self) -> HalfEdgeHandle<C, MANIFOLD>
{
unsafe {
if MANIFOLD
{
let half_edge_id =
(*self.mesh_data).vert_ref(self.id).arc.to_half_edge_id();
HalfEdgeHandle {
mesh_data: self.mesh_data,
id: half_edge_id,
}
}
else
{
self.edge().half_edge()
}
}
}
pub fn iter_star_edges(&self) -> impl Iterator<Item = EdgeHandle<C, MANIFOLD>>
{
if !MANIFOLD
{
NonManifoldStarIterator::new(self.edge(), self.id())
}
else
{
panic!("Calling edge iterator on a manifold mesh.")
}
}
pub fn iter_star_half_edges(&self) -> AgnosticStarHalfEdgeIterator<C, MANIFOLD>
{
if !MANIFOLD
{
AgnosticStarHalfEdgeIterator::NonManifold(
NonManifoldUniqueStarHalfEdgesIterator::new(self.edge(), self.id()),
)
}
else
{
AgnosticStarHalfEdgeIterator::Manifold(ManifoldStarIterator::new(
self.half_edge(),
))
}
}
pub fn valence(&self) -> usize { self.iter_star_half_edges().count() }
pub fn is_in_boundary(&self) -> bool
{
self.iter_star_half_edges().any(|h| h.is_in_boundary())
}
pub fn iter_neighbours(
&self,
) -> impl Iterator<Item = VertHandle<C, MANIFOLD>> + use<C, MANIFOLD>
{
self.iter_star_half_edges().map(|h| h.dest())
}
pub fn iter_incident_faces(
&self,
) -> impl Iterator<Item = FaceHandle<C, MANIFOLD>> + use<C, MANIFOLD>
{
self.iter_star_half_edges().filter_map(|h| {
let face = h.face();
if face.id().is_void()
{
return None;
}
Some(face)
})
}
pub fn unclean_delete(self)
{
unsafe {
let handle = VertHandle {
mesh_data: self.mesh_data,
id: self.id(),
};
if MANIFOLD
{
let half_edges: Vec<_> =
handle.iter_star_half_edges().map(|h| h.id()).collect();
for h in half_edges
{
if (*self.mesh_data).half_edge_ref(h).id.is_void()
{
continue;
}
HalfEdgeHandle {
mesh_data: self.mesh_data,
id: h,
}
.unclean_delete();
}
}
else
{
let edges: Vec<_> = handle.iter_star_edges().map(|h| h.id()).collect();
for e in edges
{
if (*self.mesh_data).edge_ref(e).id.is_void()
{
continue;
}
EdgeHandle {
mesh_data: self.mesh_data,
id: e,
}
.unclean_delete();
}
}
(*self.mesh_data)
.topology_data
.available_vert_ids
.push(self.id);
*(*self.mesh_data).vert_mut(self.id) = TopoVert::default();
}
}
pub fn delete(self) { self.unclean_delete(); }
pub fn is_connected_to(&self, other: VertId) -> bool
{
if MANIFOLD
{
self.iter_star_half_edges().any(|h| h.dest().id == other)
}
else
{
self.iter_star_edges()
.any(|e| e.endpoints().contains(&other))
}
}
pub fn shared_edge(&self, other: VertId) -> Option<HalfEdgeHandle<C, MANIFOLD>>
{
self.iter_star_half_edges()
.find(|h| h.dest().id() == other || h.source().id() == other)
}
pub fn boundary_half_edge(&self) -> Option<HalfEdgeHandle<C, MANIFOLD>>
{
self.iter_star_half_edges()
.find(|h| h.face().id().is_void())
}
pub fn normal<S>(&self) -> VertData<C>
where
VertData<C>:
linear_isomorphic::InnerSpace<S> + std::ops::Neg<Output = VertData<C>>,
S: linear_isomorphic::RealField,
{
let mut normal = VertData::<C>::default();
for f in self.iter_incident_faces()
{
normal += f.normal();
}
normal.normalized()
}
pub(crate) fn find_distinct_edge(
&self,
hid: HalfEdgeId,
) -> Option<HalfEdgeHandle<C, MANIFOLD>>
{
self.iter_star_half_edges().find(|h| {
if MANIFOLD
{
h.id() != hid
}
else
{
h.edge().id() != unsafe { (*self.mesh_data).half_edge_ref(hid).edge }
}
})
}
}
pub enum AgnosticStarHalfEdgeIterator<C: MeshStorage, const MANIFOLD: bool>
{
Manifold(ManifoldStarIterator<C, MANIFOLD>),
NonManifold(NonManifoldUniqueStarHalfEdgesIterator<C, MANIFOLD>),
}
impl<C: MeshStorage, const MANIFOLD: bool> Iterator
for AgnosticStarHalfEdgeIterator<C, MANIFOLD>
{
type Item = HalfEdgeHandle<C, MANIFOLD>;
fn next(&mut self) -> Option<Self::Item>
{
match self
{
Self::Manifold(iter) => iter.next(),
Self::NonManifold(iter) => iter.next(),
}
}
}
pub struct ManifoldStarIterator<C: MeshStorage, const MANIFOLD: bool>
{
start: HalfEdgeId,
current: HalfEdgeHandle<C, MANIFOLD>,
finished: bool,
}
impl<C: MeshStorage, const MANIFOLD: bool> ManifoldStarIterator<C, MANIFOLD>
{
pub(crate) fn new(hedge: HalfEdgeHandle<C, MANIFOLD>) -> Self
{
Self {
start: hedge.id(),
current: hedge,
finished: false,
}
}
}
impl<C: MeshStorage, const MANIFOLD: bool> Iterator for ManifoldStarIterator<C, MANIFOLD>
{
type Item = HalfEdgeHandle<C, MANIFOLD>;
fn next(&mut self) -> Option<Self::Item>
{
if self.finished || self.current.id().is_void()
{
return None;
}
let current_edge = self.current.replicate();
self.current = self.current.orbit_next().face_next();
if self.current.id() == self.start
{
self.finished = true;
}
Some(current_edge)
}
}
pub struct NonManifoldStarIterator<C: MeshStorage, const MANIFOLD: bool>
{
start: EdgeId,
current: EdgeHandle<C, MANIFOLD>,
locus: VertId,
finished: bool,
}
impl<C: MeshStorage, const MANIFOLD: bool> NonManifoldStarIterator<C, MANIFOLD>
{
pub(crate) fn new(edge: EdgeHandle<C, MANIFOLD>, locus: VertId) -> Self
{
Self {
start: edge.id(),
current: edge,
locus,
finished: false,
}
}
}
impl<C: MeshStorage, const MANIFOLD: bool> Iterator
for NonManifoldStarIterator<C, MANIFOLD>
{
type Item = EdgeHandle<C, MANIFOLD>;
fn next(&mut self) -> Option<Self::Item>
{
if self.finished || self.current.id().is_void()
{
return None;
}
let current_edge = self.current.replicate();
self.current = self.current.next_at(self.locus);
if self.current.id() == self.start
{
self.finished = true;
}
Some(current_edge)
}
}
pub struct NonManifoldStarHalfEdgesIterator<C: MeshStorage, const MANIFOLD: bool>
{
start: EdgeId,
current_edge: EdgeHandle<C, MANIFOLD>,
current_hedge_iter: OrbitHalfEdgeIterator<C, MANIFOLD>,
locus: VertId,
}
impl<C: MeshStorage, const MANIFOLD: bool> Iterator
for NonManifoldStarHalfEdgesIterator<C, MANIFOLD>
{
type Item = HalfEdgeHandle<C, MANIFOLD>;
fn next(&mut self) -> Option<Self::Item>
{
if self.current_edge.id().is_void()
{
return None;
}
if let Some(hedge) = self.current_hedge_iter.next()
{
return Some(hedge);
}
loop
{
self.current_edge = self.current_edge.next_at(self.locus);
let hedge = self.current_edge.half_edge();
self.current_hedge_iter = hedge.iter_orbit();
if let Some(handle) = self.current_hedge_iter.next()
{
return Some(handle);
}
if self.current_edge.id() == self.start
{
return None;
}
}
}
}
pub struct NonManifoldUniqueStarHalfEdgesIterator<C: MeshStorage, const MANIFOLD: bool>
{
start: EdgeId,
current_edge: EdgeHandle<C, MANIFOLD>,
locus: VertId,
finished: bool,
}
impl<C: MeshStorage, const MANIFOLD: bool>
NonManifoldUniqueStarHalfEdgesIterator<C, MANIFOLD>
{
pub(crate) fn new(edge: EdgeHandle<C, MANIFOLD>, locus: VertId) -> Self
{
Self {
start: edge.id(),
current_edge: edge,
locus,
finished: false,
}
}
}
impl<C: MeshStorage, const MANIFOLD: bool> Iterator
for NonManifoldUniqueStarHalfEdgesIterator<C, MANIFOLD>
{
type Item = HalfEdgeHandle<C, MANIFOLD>;
fn next(&mut self) -> Option<Self::Item>
{
if self.current_edge.id().is_void()
{
return None;
}
loop
{
let current_edge = self.current_edge.replicate();
if self.current_edge.id() == self.start && self.finished
{
return None;
}
self.finished = true;
self.current_edge = self.current_edge.next_at(self.locus);
let hedge = current_edge.half_edge();
if let Some(handle) =
hedge.iter_orbit().find(|h| h.source().id() == self.locus)
{
return Some(handle);
}
}
}
}