Skip to main content

conspire/geometry/mesh/from/voxels/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::{
5    geometry::{
6        Coordinate, Coordinates,
7        grid::Voxels,
8        mesh::{Connectivities, Connectivity, Mesh},
9    },
10    math::{Set, Tensor, TensorVec},
11};
12use std::collections::BTreeMap;
13
14impl Mesh<3> {
15    pub fn from_voxels<T>(voxels: Voxels<T>, remove: Option<&[T]>) -> Self
16    where
17        T: Copy + PartialEq + Into<usize>,
18    {
19        Self::from_voxels_embedded(
20            voxels,
21            remove,
22            &Coordinate::from([1.0; 3]),
23            &Coordinate::from([0.0; 3]),
24        )
25    }
26    pub(super) fn from_voxels_embedded<T>(
27        voxels: Voxels<T>,
28        remove: Option<&[T]>,
29        scale: &Coordinate<3>,
30        translate: &Coordinate<3>,
31    ) -> Self
32    where
33        T: Copy + PartialEq + Into<usize>,
34    {
35        let [nx, ny, nz] = *voxels.nel();
36        let (nxp, nyp, nzp) = (nx + 1, ny + 1, nz + 1);
37        let layer = nxp * nyp;
38        let nodes_unfiltered = layer * nzp;
39        let mut connectivity = Vec::with_capacity(voxels.len());
40        let mut materials = Vec::with_capacity(voxels.len());
41        for ([i, j, k], &block) in voxels.logical_iter() {
42            if remove.is_none_or(|ids| !ids.contains(&block)) {
43                let base = i + nxp * j + layer * k;
44                let top = base + layer;
45                connectivity.push([
46                    base,
47                    base + 1,
48                    base + nxp + 1,
49                    base + nxp,
50                    top,
51                    top + 1,
52                    top + nxp + 1,
53                    top + nxp,
54                ]);
55                materials.push(block.into());
56            }
57        }
58        let mut used = vec![false; nodes_unfiltered];
59        connectivity
60            .iter()
61            .for_each(|nodes| nodes.iter().for_each(|&node| used[node] = true));
62        let mut mapping = vec![0usize; nodes_unfiltered];
63        let mut coordinates = Coordinates::new();
64        for (old, &is_used) in used.iter().enumerate() {
65            if is_used {
66                mapping[old] = coordinates.len();
67                let x = old % nxp;
68                let y = old / nxp % nyp;
69                let z = old / layer;
70                coordinates.push(Coordinate::const_from([
71                    x as f64 * scale[0] + translate[0],
72                    y as f64 * scale[1] + translate[1],
73                    z as f64 * scale[2] + translate[2],
74                ]));
75            }
76        }
77        connectivity
78            .iter_mut()
79            .for_each(|nodes| nodes.iter_mut().for_each(|node| *node = mapping[*node]));
80        let mut blocks = BTreeMap::<usize, Vec<_>>::new();
81        connectivity
82            .into_iter()
83            .zip(materials)
84            .for_each(|(nodes, material)| blocks.entry(material).or_default().push(nodes));
85        let mut connectivities = Vec::with_capacity(blocks.len());
86        let mut numbers = Vec::with_capacity(blocks.len());
87        for (material, hexes) in blocks {
88            numbers.push(material);
89            connectivities.push(Connectivity::Hexahedral(hexes.into()));
90        }
91        (
92            Connectivities::from((connectivities, numbers)),
93            Set::from(coordinates),
94        )
95            .into()
96    }
97}