polyhedron 0.1.0

A half edge and radial edge implementation.
Documentation
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, VertData, VertId};

/// Topological handle to a vertex.
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 }
    }

    /// Id of the handle.
    pub fn id(&self) -> VertId { self.id }

    /// Is this vertex connected to anything?
    pub fn is_isolated(&self) -> bool
    {
        unsafe { (*self.mesh_data).vert_ref(self.id).arc.is_void() }
    }

    /// Read the stored data for this vertex.
    pub fn read_data(&self) -> &VertData<C>
    {
        unsafe {
            (*self.mesh_data)
                .geometry_data
                .vert_data
                .read(self.id.to_index() as u64)
        }
    }

    /// Update the stored data for this vertex.
    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)
        }
    }

    /// Handle to an edge connected to this vertex (Non Manifold only).
    /// Call only if you are certain it exists.
    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,
            }
        }
    }

    /// Handle a the half edge connected to this vertex.
    /// Call only if you are certain it exists.
    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()
            }
        }
    }

    /// Iterate over the edges centered at this point (Non Manifold only).
    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.")
        }
    }

    /// Iterate over the half edges with this vertex as their source.
    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(),
            ))
        }
    }

    /// Compute the valence of the vertex.
    pub fn valence(&self) -> usize { self.iter_star_half_edges().count() }

    /// Is there a boundary edge that touches this vertex?
    pub fn is_in_boundary(&self) -> bool
    {
        self.iter_star_half_edges().any(|h| h.is_in_boundary())
    }

    /// Iterate over the vertices sharing an edge with this vertex.
    pub fn iter_neighbours(&self) -> impl Iterator<Item = VertHandle<C, MANIFOLD>>
    {
        self.iter_star_half_edges().map(|h| h.dest())
    }

    /// Iterate over the faces touching this vertex.
    pub fn iter_incident_faces(&self) -> impl Iterator<Item = FaceHandle<C, MANIFOLD>>
    {
        self.iter_star_half_edges().map(|h| h.face())
    }

    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 }
            }
        })
    }
}

/// Iterator over the half edges of a vertex.
pub enum AgnosticStarHalfEdgeIterator<C: MeshStorage, const MANIFOLD: bool>
{
    /// The iterator assumes manifold topology.
    Manifold(ManifoldStarIterator<C, MANIFOLD>),
    /// The iterator assumes non-manifold topology.
    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(),
        }
    }
}

/// Iterator over the half edges of a vertex.
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();

        // Check if we've completed the loop
        if self.current.id() == self.start
        {
            self.finished = true;
        }

        Some(current_edge)
    }
}

/// Iterator over the half edges of a vertex.
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);

        // Check if we've completed the loop
        if self.current.id() == self.start
        {
            self.finished = true;
        }

        Some(current_edge)
    }
}

/// Iterator over the half edges of a vertex.
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> NonManifoldStarHalfEdgesIterator<C, MANIFOLD>
{
    pub(crate) fn new(edge: EdgeHandle<C, MANIFOLD>, locus: VertId) -> Self
    {
        Self {
            start: edge.id(),
            current_hedge_iter: OrbitHalfEdgeIterator::new(edge.half_edge()),
            current_edge: edge,
            locus,
        }
    }
}

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);
            }

            // Check if we've completed the loop.
            if self.current_edge.id() == self.start
            {
                return None;
            }
        }
    }
}

/// Iterator over the half edges of a vertex.
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();
            // Check if we've completed the loop.
            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);
            }
        }
    }
}