polyhedron 0.1.0

A half edge and radial edge implementation.
Documentation
use crate::*;

/// Verify that the pointers of the underlying mesh obey reasonable values
/// according to the specified topology constraints (Manifold vs NonManifold).
/// If this returns an error, consider the mesh unusable.
pub fn verify_correctness<C: MeshStorage, const M: bool>(
    mesh: &PolyHedron<C, M>,
) -> Result<(), String>
{
    if unsafe { (*mesh.mesh_data.get()).geometry_data.vert_data.len() }
        != unsafe { (*mesh.mesh_data.get()).topology_data.topo_verts.len() }
    {
        return Err(format!(
            "Vertex data count does not match topological vertex count."
        ));
    }

    let edge_data_len = unsafe { (*mesh.mesh_data.get()).geometry_data.edge_data.len() };
    if edge_data_len != 0
    {
        let topo_edges = if M
        {
            let topo_edge_count =
                unsafe { (*mesh.mesh_data.get()).topology_data.topo_half_edges.len() };
            topo_edge_count / 2
        }
        else
        {
            let topo_edge_count =
                unsafe { (*mesh.mesh_data.get()).topology_data.topo_edges.len() };
            topo_edge_count
        };

        if topo_edges != edge_data_len
        {
            return Err(format!(
                "Edge data count does not match topological edge count."
            ));
        }
    }

    let face_data_len = unsafe { (*mesh.mesh_data.get()).geometry_data.face_data.len() };
    if face_data_len != 0
    {
        let topo_face_count =
            unsafe { (*mesh.mesh_data.get()).topology_data.topo_faces.len() };

        if topo_face_count != face_data_len
        {
            return Err(format!(
                "Face data count does not match topological face count."
            ));
        }
    }

    for vert_index in 0..mesh.vert_count()
    {
        let vert = unsafe { (*mesh.mesh_data.get()).vert_ref(VertId::new(vert_index)) };
        if vert.id.is_void()
        {
            continue;
        }

        let active_vid = vert.id;
        if !M
        {
            let edge_id = vert.arc.to_edge_id();
            if !edge_id.is_void()
            {
                let edge = unsafe { (*mesh.mesh_data.get()).edge_ref(edge_id) };
                if !edge.endpoints.iter().any(|vid| *vid == active_vid)
                {
                    return Err(format!(
                        "Vertex at index {} points to edge {} but the edge doesn't point back to it.",
                        vert_index, edge_id
                    ));
                }
            }
        }
    }

    for edge_index in 0..unsafe { (*mesh.mesh_data.get()).edge_count() * (!M as usize) }
    {
        let edge = unsafe { (*mesh.mesh_data.get()).edge_ref(EdgeId::new(edge_index)) };

        let id = edge.id;
        let endpoints = edge.endpoints;
        let cycles = edge.endpoint_cycles;
        let half_edge = edge.half_edge;

        if id.is_void()
        {
            continue;
        }

        if endpoints.iter().any(|vid| vid.is_void())
        {
            return Err(format!(
                "Edge at index {} has an void endpoint [{} {}].",
                edge_index, endpoints[0], endpoints[1]
            ));
        }

        if cycles[0].prev.is_void() || cycles[0].next.is_void()
        {
            return Err(format!(
                "Edge at index {} has a broken cycle [p: {}, n: {}].",
                edge_index, cycles[0].prev, cycles[0].next
            ));
        }

        if cycles[1].prev.is_void() || cycles[1].next.is_void()
        {
            return Err(format!(
                "Edge at index {} has a broken cycle [p: {}, n: {}].",
                edge_index, cycles[1].prev, cycles[1].next
            ));
        }

        for (i, prev_id) in [cycles[0].prev, cycles[1].prev].into_iter().enumerate()
        {
            let prev_edge = unsafe { (*mesh.mesh_data.get()).edge_ref(prev_id) };
            let next = prev_edge.cycle_at(endpoints[i]).unwrap().next;

            if next != id
            {
                return Err(format!(
                    "Edge at index {} points to a previous edge {} that doesn't point back to it.",
                    edge_index, prev_id
                ));
            }
        }

        for (i, next_id) in [cycles[0].next, cycles[1].next].into_iter().enumerate()
        {
            let next_edge = unsafe { (*mesh.mesh_data.get()).edge_ref(next_id) };
            let prev = next_edge.cycle_at(endpoints[i]).unwrap().prev;

            if prev != id
            {
                return Err(format!(
                    "Edge at index {} points to a next edge {} that doesn't point back to it.",
                    edge_index, next_id
                ));
            }
        }

        let hedge = unsafe { (*mesh.mesh_data.get()).half_edge_ref(half_edge) };

        if hedge.edge != id
        {
            return Err(format!(
                "Edge at index {} points to a half edge {} that doesn't point back to it.",
                edge_index, hedge.edge
            ));
        }
    }

    for half_edge_index in 0..unsafe { (*mesh.mesh_data.get()).half_edge_count() }
    {
        let half_edge = unsafe {
            (*mesh.mesh_data.get()).half_edge_ref(HalfEdgeId::new(half_edge_index))
        };

        let id = half_edge.id;
        let source = half_edge.source;
        let orbit_next = half_edge.orbit_next;
        let face_next = half_edge.face_next;
        let face_prev = half_edge.face_prev;
        let edge = half_edge.edge;

        if id.is_void()
        {
            continue;
        }

        if source.is_void()
        {
            return Err(format!(
                "Half edge at index {} has a void source.",
                half_edge_index
            ));
        }

        if orbit_next.is_void()
        {
            return Err(format!(
                "Half edge at index {} has a void next orbit.",
                half_edge_index
            ));
        }

        if face_next.is_void()
        {
            return Err(format!(
                "Half edge at index {} has a void face next.",
                half_edge_index
            ));
        }

        let next_face = unsafe { (*mesh.mesh_data.get()).half_edge_ref(face_next) };

        let prev_id = next_face.face_prev;
        if prev_id != id
        {
            return Err(format!(
                "Half edge at index {} points to next in face half edge {}, who's prev is {}.",
                half_edge_index, next_face.id, next_face.face_prev
            ));
        }

        if face_prev.is_void()
        {
            return Err(format!(
                "Half edge at index {} has a void face prev.",
                half_edge_index
            ));
        }

        let prev_face = unsafe { (*mesh.mesh_data.get()).half_edge_ref(face_prev) };

        let prev_id = prev_face.face_next;
        if prev_id != id
        {
            return Err(format!(
                "Half edge at index {} points to prev in face half edge {}, who's next is {}.",
                half_edge_index, prev_face.id, prev_face.face_next
            ));
        }

        if !M
        {
            if edge.is_void()
            {
                return Err(format!(
                    "Half edge at index {} points to a void edge",
                    half_edge_index,
                ));
            }
        }
    }

    for face_index in 0..unsafe { (*mesh.mesh_data.get()).face_count() }
    {
        let face = unsafe { (*mesh.mesh_data.get()).face_ref(FaceId::new(face_index)) };
        if face.id.is_void()
        {
            continue;
        }

        let id = face.id;
        let hedge = face.half_edge;

        if hedge.is_void()
        {
            return Err(format!(
                "Face at index {} points to a void half edge.",
                face_index,
            ));
        }

        let fid = unsafe { (*mesh.mesh_data.get()).half_edge_ref(hedge).face };
        if fid != id
        {
            return Err(format!(
                "Face at index {} points to half edge {} that doesn't point back to it.",
                face_index, hedge
            ));
        }

        let mut current_edge = hedge;
        let starting_edge = current_edge;
        let mut safety_counter = 0;
        loop
        {
            safety_counter += 1;
            if safety_counter > 500
            {
                return Err(format!(
                    "Face {} has an edge cycle with over 500 elements, not strictly an error but highly suspicious, check was short circuited.",
                    face_index,
                ));
            }

            let hedge = unsafe { (*mesh.mesh_data.get()).half_edge_ref(current_edge) };
            if hedge.face != id
            {
                return Err(format!(
                    "Face at index {} points to half edge {} that doesn't point back to it.",
                    face_index, hedge.id
                ));
            }

            current_edge = hedge.face_next;

            if current_edge == starting_edge
            {
                break;
            }
        }
    }

    Ok(())
}