polyhedron 0.1.3

A half edge and radial edge implementation.
Documentation
use crate::data_container::StorageBuffer;
use crate::prelude::{half_edge_handle::HalfEdgeHandle, vert_handle::VertHandle};
use crate::{ArcId, EdgeId, EndpointList, MeshData, MeshStorage, VertId};
use crate::{EdgeData, TopoEdge};

/// Topological handle to an edge (non-manifold only).
pub struct EdgeHandle<C: MeshStorage, const MANIFOLD: bool>
{
    pub(crate) mesh_data: *mut MeshData<C, MANIFOLD>,
    pub(crate) id: EdgeId,
}

impl<C: MeshStorage, const MANIFOLD: bool> EdgeHandle<C, MANIFOLD>
{
    /// Id of the handle.
    pub fn id(&self) -> EdgeId { self.id }

    /// Whether there are any half edges orbitting this eedge.
    pub fn is_thin(&self) -> bool
    {
        unsafe { (*self.mesh_data).edge_ref(self.id).half_edge.is_void() }
    }

    /// Handle to a random half edge orbitting this edge.
    pub fn half_edge(&self) -> HalfEdgeHandle<C, MANIFOLD>
    {
        unsafe {
            let half_edge_id = (*self.mesh_data).edge_ref(self.id).half_edge;

            HalfEdgeHandle {
                mesh_data: self.mesh_data,
                id: half_edge_id,
            }
        }
    }

    /// Ids of both endpoints of the edge in o particular order.
    pub fn endpoints(&self) -> [VertId; 2]
    {
        unsafe { (*self.mesh_data).edge_ref(self.id).endpoints }
    }

    /// Handles to both endpoints of the edge in o particular order.
    pub fn endpoint_handles(&self) -> [VertHandle<C, MANIFOLD>; 2]
    {
        let [v1, v2] = self.endpoints();
        [
            VertHandle::new(self.mesh_data, v1),
            VertHandle::new(self.mesh_data, v2),
        ]
    }

    /// Next edge in the radial cycle of the given endpoint (will crash
    /// if the specified vertex id is not in the edge).
    pub fn next_at(&self, v: VertId) -> Self
    {
        unsafe {
            let next_id = (*self.mesh_data)
                .edge_ref(self.id)
                .cycle_at(v)
                .unwrap()
                .next;

            EdgeHandle {
                mesh_data: self.mesh_data,
                id: next_id,
            }
        }
    }

    /// Previous edge in the radial cycle of the given endpoint (will crash
    /// if the specified vertex id is not in the edge).
    pub fn prev_at(&self, v: VertId) -> Self
    {
        unsafe {
            let prev_id = (*self.mesh_data)
                .edge_ref(self.id)
                .cycle_at(v)
                .unwrap()
                .prev;

            EdgeHandle {
                mesh_data: self.mesh_data,
                id: prev_id,
            }
        }
    }

    /// Make a shallow copy of the handle.
    pub fn replicate(&self) -> Self
    {
        EdgeHandle {
            mesh_data: self.mesh_data,
            id: self.id,
        }
    }

    /// Remove this edge without cleaning the remaining vertices. It will
    /// remove faces and half edges however.
    pub fn unclean_delete(self)
    {
        unsafe {
            let handle = EdgeHandle {
                mesh_data: self.mesh_data,
                id: self.id,
            };

            let half_edges: Vec<_> =
                handle.half_edge().iter_orbit().map(|h| h.id()).collect();

            for h in half_edges
            {
                let hedge_ref = (*self.mesh_data).half_edge_ref(h);
                if hedge_ref.id.is_void()
                {
                    continue;
                }

                let handle = HalfEdgeHandle {
                    mesh_data: self.mesh_data,
                    id: h,
                };
                handle.unclean_delete();
            }

            self.remove_from_cycles();

            (*self.mesh_data)
                .topology_data
                .available_edge_ids
                .push(self.id);
            *(*self.mesh_data).edge_mut(self.id) = TopoEdge::default();
        }
    }

    /// Delete this edge and any isolated points left after its removal.
    pub fn delete(self)
    {
        let [v1, v2] = self.endpoints();

        let mesh_data = self.mesh_data;
        self.unclean_delete();

        let vert1 = VertHandle { mesh_data, id: v1 };
        let should_delete_v1 = vert1.iter_star_edges().count() == 0;
        if should_delete_v1
        {
            vert1.delete();
        }

        let vert2 = VertHandle { mesh_data, id: v2 };
        let should_delete_2 = vert2.iter_star_edges().count() == 0;
        if should_delete_2
        {
            vert2.delete();
        }
    }

    pub(crate) fn remove_from_cycles(&self)
    {
        assert!(!MANIFOLD);
        let [v1, v2] = self.endpoint_handles();

        if let Some(h) = v1.find_distinct_edge(self.half_edge().id())
        {
            unsafe {
                (*self.mesh_data).vert_mut(v1.id()).arc = ArcId::Edge(h.edge().id())
            };
        }
        else
        {
            unsafe {
                (*self.mesh_data).vert_mut(v1.id()).arc = ArcId::Edge(EdgeId::default());
            };
        };

        if let Some(h) = v2.find_distinct_edge(self.half_edge().id())
        {
            unsafe {
                (*self.mesh_data).vert_mut(v2.id()).arc = ArcId::Edge(h.edge().id());
            };
        }
        else
        {
            unsafe {
                (*self.mesh_data).vert_mut(v2.id()).arc = ArcId::Edge(EdgeId::default());
            };
        };

        unsafe {
            let edges = &mut (*self.mesh_data).topology_data.topo_edges;
            EndpointList::remove_edge(edges, self.id(), v1.id());
            EndpointList::remove_edge(edges, self.id(), v2.id());
        }
    }

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

    /// Update the stored data for this edge.
    pub fn update_data<F: FnMut(&mut EdgeData<C>)>(&mut self, update: F)
    {
        unsafe {
            (*self.mesh_data)
                .geometry_data
                .edge_data
                .update(self.id.to_index() as u64, update)
        }
    }
}