conspire/geometry/mesh/from/pixels/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 geometry::{
6 Coordinate, Coordinates,
7 grid::Pixels,
8 mesh::{Connectivities, Connectivity, Mesh},
9 },
10 math::{Set, Tensor, TensorVec},
11};
12use std::collections::BTreeMap;
13
14impl Mesh<2> {
15 pub fn from_pixels<T>(pixels: Pixels<T>, remove: Option<&[T]>) -> Self
16 where
17 T: Copy + PartialEq + Into<usize>,
18 {
19 let [nx, ny] = *pixels.nel();
20 let (nxp, nyp) = (nx + 1, ny + 1);
21 let nodes_unfiltered = nxp * nyp;
22 let mut connectivity = Vec::with_capacity(pixels.len());
23 let mut materials = Vec::with_capacity(pixels.len());
24 for ([i, j], &block) in pixels.logical_iter() {
25 if remove.is_none_or(|ids| !ids.contains(&block)) {
26 let base = i + nxp * j;
27 connectivity.push([base, base + 1, base + nxp + 1, base + nxp]);
28 materials.push(block.into());
29 }
30 }
31 let mut used = vec![false; nodes_unfiltered];
32 connectivity
33 .iter()
34 .for_each(|nodes| nodes.iter().for_each(|&node| used[node] = true));
35 let mut mapping = vec![0usize; nodes_unfiltered];
36 let mut coordinates = Coordinates::new();
37 for (old, &is_used) in used.iter().enumerate() {
38 if is_used {
39 mapping[old] = coordinates.len();
40 let x = old % nxp;
41 let y = old / nxp;
42 coordinates.push(Coordinate::const_from([x as f64, y as f64]));
43 }
44 }
45 connectivity
46 .iter_mut()
47 .for_each(|nodes| nodes.iter_mut().for_each(|node| *node = mapping[*node]));
48 let mut blocks = BTreeMap::<usize, Vec<_>>::new();
49 connectivity
50 .into_iter()
51 .zip(materials)
52 .for_each(|(nodes, material)| blocks.entry(material).or_default().push(nodes));
53 let mut connectivities = Vec::with_capacity(blocks.len());
54 let mut numbers = Vec::with_capacity(blocks.len());
55 for (material, quads) in blocks {
56 numbers.push(material);
57 connectivities.push(Connectivity::Quadrilateral(quads.into()));
58 }
59 (
60 Connectivities::from((connectivities, numbers)),
61 Set::from(coordinates),
62 )
63 .into()
64 }
65}