axiolid_mesh/
component.rs1use crate::TriMesh;
12use std::collections::BTreeMap;
13
14struct Partition {
16 parent: Vec<usize>,
17}
18
19impl Partition {
20 fn new(count: usize) -> Self {
21 Self {
22 parent: (0..count).collect(),
23 }
24 }
25
26 fn find(&mut self, mut node: usize) -> usize {
27 while self.parent[node] != node {
28 self.parent[node] = self.parent[self.parent[node]];
29 node = self.parent[node];
30 }
31 node
32 }
33
34 fn union(&mut self, a: usize, b: usize) {
35 let (ra, rb) = (self.find(a), self.find(b));
36 if ra != rb {
37 self.parent[rb] = ra;
38 }
39 }
40}
41
42fn partition_of(mesh: &TriMesh) -> Partition {
44 let mut partition = Partition::new(mesh.positions.len());
45 for triangle in mesh.indices.chunks_exact(3) {
46 let first = triangle[0] as usize;
47 for corner in &triangle[1..] {
48 partition.union(first, *corner as usize);
49 }
50 }
51 partition
52}
53
54pub fn component_count(mesh: &TriMesh) -> usize {
58 if mesh.indices.is_empty() {
59 return 0;
60 }
61 let mut partition = partition_of(mesh);
62 let mut roots = std::collections::BTreeSet::new();
63 for index in &mesh.indices {
64 let root = partition.find(*index as usize);
65 roots.insert(root);
66 }
67 roots.len()
68}
69
70pub fn decompose(mesh: &TriMesh) -> Vec<TriMesh> {
79 if mesh.indices.is_empty() {
80 return Vec::new();
81 }
82 let mut partition = partition_of(mesh);
83
84 let mut order: BTreeMap<usize, usize> = BTreeMap::new();
87 let mut groups: Vec<Vec<usize>> = Vec::new();
88 for (triangle_index, triangle) in mesh.indices.chunks_exact(3).enumerate() {
89 let root = partition.find(triangle[0] as usize);
90 let slot = *order.entry(root).or_insert_with(|| {
91 groups.push(Vec::new());
92 groups.len() - 1
93 });
94 groups[slot].push(triangle_index);
95 }
96
97 if groups.len() == 1 && mesh.positions.len() == referenced(mesh) {
101 return vec![mesh.clone()];
102 }
103
104 groups
105 .into_iter()
106 .map(|triangles| extract(mesh, &triangles))
107 .collect()
108}
109
110fn referenced(mesh: &TriMesh) -> usize {
112 mesh.indices
113 .iter()
114 .collect::<std::collections::BTreeSet<_>>()
115 .len()
116}
117
118fn extract(mesh: &TriMesh, triangles: &[usize]) -> TriMesh {
123 let mut remap: BTreeMap<u32, u32> = BTreeMap::new();
124 let mut positions = Vec::new();
125 let mut indices = Vec::with_capacity(triangles.len() * 3);
126 for &triangle in triangles {
127 for corner in 0..3 {
128 let old = mesh.indices[triangle * 3 + corner];
129 let new = *remap.entry(old).or_insert_with(|| {
130 positions.push(mesh.positions[old as usize]);
131 (positions.len() - 1) as u32
132 });
133 indices.push(new);
134 }
135 }
136 TriMesh::new(positions, indices)
137}
138
139pub fn compose(meshes: &[TriMesh]) -> TriMesh {
146 let mut positions = Vec::new();
147 let mut indices = Vec::new();
148 for mesh in meshes {
149 let base = positions.len() as u32;
150 positions.extend_from_slice(&mesh.positions);
151 indices.extend(mesh.indices.iter().map(|index| index + base));
152 }
153 TriMesh::new(positions, indices)
154}