use crate::math::{Real, Vector, DIM};
use alloc::vec::Vec;
#[cfg(feature = "dim3")]
mod cover_octree;
#[cfg(feature = "dim3")]
mod cover_smoothing;
#[cfg(feature = "dim2")]
mod delaunay_refinement;
#[cfg(feature = "dim3")]
mod isosurface_stuffing;
#[derive(Clone, Debug, Default)]
#[cfg_attr(
feature = "serde-serialize",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct VolumeMesh {
pub vertices: Vec<Vector>,
pub cells: Vec<[u32; DIM + 1]>,
}
#[cfg(feature = "dim3")]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub enum MeshEnclosure {
#[default]
Cover,
Crust,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct VolumeMeshParameters {
pub cell_size: Real,
#[cfg(feature = "dim2")]
pub min_angle: Real,
#[cfg(feature = "dim3")]
pub enclosure: MeshEnclosure,
#[cfg(feature = "dim3")]
pub cover_smoothing: u32,
#[cfg(feature = "dim3")]
pub cover_guard: Real,
#[cfg(feature = "dim3")]
pub cover_subdivisions: u32,
}
impl VolumeMeshParameters {
pub fn new(cell_size: Real) -> Self {
Self {
cell_size,
#[cfg(feature = "dim2")]
#[cfg_attr(feature = "f64", expect(clippy::unnecessary_cast))]
min_angle: core::f64::consts::PI as Real / 6.0,
#[cfg(feature = "dim3")]
enclosure: MeshEnclosure::Cover,
#[cfg(feature = "dim3")]
cover_smoothing: 0,
#[cfg(feature = "dim3")]
cover_guard: 0.15,
#[cfg(feature = "dim3")]
cover_subdivisions: 0,
}
}
}
pub fn volume_mesh(
vertices: &[Vector],
indices: &[[u32; DIM]],
params: &VolumeMeshParameters,
) -> Option<VolumeMesh> {
#[cfg(feature = "dim2")]
{
delaunay_refinement::triangulate(vertices, indices, params)
}
#[cfg(feature = "dim3")]
{
isosurface_stuffing::tetrahedralize(vertices, indices, params)
}
}
impl VolumeMesh {
pub fn connected_components(&self) -> Vec<u32> {
let mut parent: Vec<u32> = (0..self.vertices.len() as u32).collect();
fn root(parent: &mut [u32], mut i: u32) -> u32 {
while parent[i as usize] != i {
parent[i as usize] = parent[parent[i as usize] as usize];
i = parent[i as usize];
}
i
}
for cell in &self.cells {
for vid in &cell[1..] {
let (a, b) = (root(&mut parent, cell[0]), root(&mut parent, *vid));
parent[a as usize] = b;
}
}
let mut ids = alloc::vec![u32::MAX; self.vertices.len()];
let mut count = 0;
self.cells
.iter()
.map(|cell| {
let id = &mut ids[root(&mut parent, cell[0]) as usize];
if *id == u32::MAX {
*id = count;
count += 1;
}
*id
})
.collect()
}
pub fn compact(&mut self) {
let mut remap = alloc::vec![u32::MAX; self.vertices.len()];
let mut vertices = Vec::with_capacity(self.vertices.len());
for cell in &mut self.cells {
for vid in cell {
let remapped = &mut remap[*vid as usize];
if *remapped == u32::MAX {
*remapped = vertices.len() as u32;
vertices.push(self.vertices[*vid as usize]);
}
*vid = *remapped;
}
}
self.vertices = vertices;
}
}