runmat-meshing-surface 0.6.0

Surface meshing stage for RunMat meshing
Documentation
use crate::{
    math::{cross, norm, sub, Triangle3},
    SurfaceDiscretization, SurfaceElement,
};
use runmat_meshing_cad::SourceTopologyModel;

use super::types::SurfaceValidationError;

pub(super) fn topology_face_points(
    topology: &SourceTopologyModel,
    node_ids: [u32; 3],
) -> Result<Triangle3, SurfaceValidationError> {
    Ok([
        topology_node(topology, node_ids[0])?,
        topology_node(topology, node_ids[1])?,
        topology_node(topology, node_ids[2])?,
    ])
}

pub(super) fn surface_element_points(
    surface: &SurfaceDiscretization,
    element: &SurfaceElement,
) -> Result<Triangle3, SurfaceValidationError> {
    Ok([
        surface_node(surface, element, element.node_ids[0])?,
        surface_node(surface, element, element.node_ids[1])?,
        surface_node(surface, element, element.node_ids[2])?,
    ])
}

pub(super) fn unit_normal(points: Triangle3) -> Option<[f64; 3]> {
    let normal = cross(sub(points[1], points[0]), sub(points[2], points[0]));
    let length = norm(normal);
    (length > 0.0).then_some([normal[0] / length, normal[1] / length, normal[2] / length])
}

pub(super) fn sorted_edge(left: u32, right: u32) -> [u32; 2] {
    if left <= right {
        [left, right]
    } else {
        [right, left]
    }
}

fn topology_node(
    topology: &SourceTopologyModel,
    node_id: u32,
) -> Result<[f64; 3], SurfaceValidationError> {
    topology
        .vertices
        .get(node_id as usize)
        .filter(|vertex| vertex.vertex_id == node_id)
        .map(|vertex| vertex.coordinates_m)
        .ok_or(SurfaceValidationError::MissingSurfaceNode {
            element_id: u32::MAX,
            node_id,
        })
}

fn surface_node(
    surface: &SurfaceDiscretization,
    element: &SurfaceElement,
    node_id: u32,
) -> Result<[f64; 3], SurfaceValidationError> {
    surface
        .nodes
        .get(node_id as usize)
        .filter(|node| node.node_id == node_id)
        .map(|node| node.coordinates_m)
        .ok_or(SurfaceValidationError::MissingSurfaceNode {
            element_id: element.element_id,
            node_id,
        })
}