conspire/geometry/mesh/quality/surface/
mod.rs1#[cfg(test)]
2mod test;
3mod triangles;
4
5use crate::{
6 geometry::mesh::Mesh,
7 math::{FxHashMap, FxHashSet},
8};
9
10impl<const D: usize> Mesh<D> {
11 pub fn boundary_edges(&self) -> Vec<[usize; 2]> {
12 self.edge_incidence()
13 .into_values()
14 .filter_map(|(edge, count)| (count == 1).then_some(edge))
15 .collect()
16 }
17 pub fn boundary_loops(&self) -> Vec<Vec<usize>> {
18 let mut next: FxHashMap<usize, usize> = self
19 .boundary_edges()
20 .into_iter()
21 .map(|[a, b]| (a, b))
22 .collect();
23 let mut loops = Vec::new();
24 while let Some(&start) = next.keys().next() {
25 let mut nodes = vec![start];
26 let mut node = start;
27 while let Some(following) = next.remove(&node) {
28 if following == start {
29 break;
30 }
31 nodes.push(following);
32 node = following;
33 }
34 loops.push(nodes);
35 }
36 loops
37 }
38 pub fn non_manifold_edges(&self) -> Vec<[usize; 2]> {
39 self.edge_incidence()
40 .into_values()
41 .filter_map(|(edge, count)| (count > 2).then_some(edge))
42 .collect()
43 }
44 pub fn non_manifold_seams(&self) -> Vec<Vec<[usize; 2]>> {
45 let edges = self.non_manifold_edges();
46 let mut incident = FxHashMap::<usize, Vec<usize>>::default();
47 for (e, &[a, b]) in edges.iter().enumerate() {
48 incident.entry(a).or_default().push(e);
49 incident.entry(b).or_default().push(e);
50 }
51 let mut visited = vec![false; edges.len()];
52 let mut seams = Vec::new();
53 for start in 0..edges.len() {
54 if visited[start] {
55 continue;
56 }
57 visited[start] = true;
58 let mut seam = Vec::new();
59 let mut stack = vec![start];
60 while let Some(e) = stack.pop() {
61 seam.push(edges[e]);
62 for node in edges[e] {
63 incident[&node].iter().for_each(|&other| {
64 if !visited[other] {
65 visited[other] = true;
66 stack.push(other);
67 }
68 });
69 }
70 }
71 seams.push(seam);
72 }
73 seams
74 }
75 pub fn non_manifold_vertices(&self) -> Vec<usize> {
76 let mut faces = Vec::new();
77 self.iter().for_each(|block| {
78 block
79 .iter()
80 .for_each(|element| faces.push(element.to_vec()))
81 });
82 let mut edge_faces = FxHashMap::<[usize; 2], Vec<usize>>::default();
83 let mut vertex_faces = FxHashMap::<usize, Vec<usize>>::default();
84 for (f, face) in faces.iter().enumerate() {
85 for (i, &v) in face.iter().enumerate() {
86 vertex_faces.entry(v).or_default().push(f);
87 let w = face[(i + 1) % face.len()];
88 edge_faces.entry(edge(v, w)).or_default().push(f);
89 }
90 }
91 let mut non_manifold = Vec::new();
92 for (&v, incident) in &vertex_faces {
93 let local: FxHashMap<usize, usize> =
94 incident.iter().enumerate().map(|(i, &f)| (f, i)).collect();
95 let mut parent: Vec<usize> = (0..incident.len()).collect();
96 for &f in incident {
97 let face = &faces[f];
98 let (len, pos) = (face.len(), face.iter().position(|&n| n == v).unwrap());
99 for x in [face[(pos + len - 1) % len], face[(pos + 1) % len]] {
100 if let Some(shared) = edge_faces.get(&edge(v, x))
101 && shared.len() == 2
102 {
103 union(&mut parent, local[&shared[0]], local[&shared[1]]);
104 }
105 }
106 }
107 let fans: FxHashSet<usize> =
108 (0..incident.len()).map(|i| find(&mut parent, i)).collect();
109 if fans.len() > 1 {
110 non_manifold.push(v);
111 }
112 }
113 non_manifold
114 }
115 fn edge_incidence(&self) -> FxHashMap<[usize; 2], ([usize; 2], usize)> {
116 let mut edges = FxHashMap::default();
117 self.iter().for_each(|block| {
118 let local_edges = block.local_faces();
119 block.iter().for_each(|element| {
120 local_edges.iter().for_each(|edge| {
121 let oriented = [element[edge[0]], element[edge[1]]];
122 let key = if oriented[0] < oriented[1] {
123 oriented
124 } else {
125 [oriented[1], oriented[0]]
126 };
127 edges
128 .entry(key)
129 .and_modify(|(_, count)| *count += 1)
130 .or_insert((oriented, 1));
131 })
132 })
133 });
134 edges
135 }
136}
137
138fn edge(a: usize, b: usize) -> [usize; 2] {
139 if a < b { [a, b] } else { [b, a] }
140}
141
142fn find(parent: &mut [usize], i: usize) -> usize {
143 if parent[i] != i {
144 parent[i] = find(parent, parent[i]);
145 }
146 parent[i]
147}
148
149fn union(parent: &mut [usize], a: usize, b: usize) {
150 let (a, b) = (find(parent, a), find(parent, b));
151 parent[a] = b;
152}