1use std::sync::Arc;
20
21#[derive(Debug)]
24pub struct CellArray {
25 offsets: Arc<Vec<i64>>,
26 connectivity: Arc<Vec<i64>>,
27}
28
29impl Clone for CellArray {
30 fn clone(&self) -> Self {
31 Self {
32 offsets: Arc::clone(&self.offsets),
33 connectivity: Arc::clone(&self.connectivity),
34 }
35 }
36}
37
38impl PartialEq for CellArray {
39 fn eq(&self, other: &Self) -> bool {
40 (Arc::ptr_eq(&self.offsets, &other.offsets) || *self.offsets == *other.offsets)
41 && (Arc::ptr_eq(&self.connectivity, &other.connectivity) || *self.connectivity == *other.connectivity)
42 }
43}
44
45impl Default for CellArray {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl CellArray {
52 pub fn new() -> Self {
53 Self {
54 offsets: Arc::new(vec![0]),
55 connectivity: Arc::new(Vec::new()),
56 }
57 }
58
59 pub fn from_raw(offsets: Vec<i64>, connectivity: Vec<i64>) -> Self {
61 assert!(!offsets.is_empty(), "offsets must have at least one element");
62 assert_eq!(offsets[0], 0, "first offset must be 0");
63 Self {
64 offsets: Arc::new(offsets),
65 connectivity: Arc::new(connectivity),
66 }
67 }
68
69 pub fn from_triangles(tris: &[[i64; 3]]) -> Self {
71 let mut ca = Self::new();
72 for tri in tris {
73 ca.push_cell(tri);
74 }
75 ca
76 }
77
78 pub fn from_quads(quads: &[[i64; 4]]) -> Self {
80 let mut ca = Self::new();
81 for quad in quads {
82 ca.push_cell(quad);
83 }
84 ca
85 }
86
87 pub fn push_cell(&mut self, point_ids: &[i64]) {
89 if let Some(c) = Arc::get_mut(&mut self.connectivity) {
91 c.extend_from_slice(point_ids);
92 } else {
93 Arc::make_mut(&mut self.connectivity).extend_from_slice(point_ids);
94 }
95 let conn_len = self.connectivity.len() as i64;
96 if let Some(o) = Arc::get_mut(&mut self.offsets) {
97 o.push(conn_len);
98 } else {
99 Arc::make_mut(&mut self.offsets).push(conn_len);
100 }
101 }
102
103 pub fn num_cells(&self) -> usize {
104 self.offsets.len().saturating_sub(1)
105 }
106
107 pub fn cell(&self, idx: usize) -> &[i64] {
109 let start = self.offsets[idx] as usize;
110 let end = self.offsets[idx + 1] as usize;
111 &self.connectivity[start..end]
112 }
113
114 pub fn is_empty(&self) -> bool {
115 self.num_cells() == 0
116 }
117
118 pub fn offsets(&self) -> &[i64] {
119 &self.offsets
120 }
121
122 pub fn connectivity(&self) -> &[i64] {
123 &self.connectivity
124 }
125
126 pub fn connectivity_len(&self) -> usize {
128 self.connectivity.len()
129 }
130
131 pub fn clear(&mut self) {
132 let off = Arc::make_mut(&mut self.offsets);
133 off.clear();
134 off.push(0);
135 Arc::make_mut(&mut self.connectivity).clear();
136 }
137
138 pub fn cell_size(&self, idx: usize) -> usize {
140 let start = self.offsets[idx] as usize;
141 let end = self.offsets[idx + 1] as usize;
142 end - start
143 }
144
145 pub fn cell_sizes(&self) -> impl Iterator<Item = usize> + '_ {
147 (0..self.num_cells()).map(move |i| self.cell_size(i))
148 }
149
150 pub fn max_cell_size(&self) -> usize {
152 self.cell_sizes().max().unwrap_or(0)
153 }
154
155 pub fn is_homogeneous(&self) -> Option<usize> {
157 let mut sizes = self.cell_sizes();
158 let first = sizes.next()?;
159 if sizes.all(|s| s == first) { Some(first) } else { None }
160 }
161
162 pub fn iter(&self) -> CellIter<'_> {
164 CellIter {
165 cells: self,
166 idx: 0,
167 }
168 }
169}
170
171pub struct CellIter<'a> {
172 cells: &'a CellArray,
173 idx: usize,
174}
175
176impl<'a> Iterator for CellIter<'a> {
177 type Item = &'a [i64];
178
179 fn next(&mut self) -> Option<Self::Item> {
180 if self.idx >= self.cells.num_cells() {
181 return None;
182 }
183 let cell = self.cells.cell(self.idx);
184 self.idx += 1;
185 Some(cell)
186 }
187
188 fn size_hint(&self) -> (usize, Option<usize>) {
189 let remaining = self.cells.num_cells() - self.idx;
190 (remaining, Some(remaining))
191 }
192}
193
194impl ExactSizeIterator for CellIter<'_> {}
195
196impl<'a> IntoIterator for &'a CellArray {
197 type Item = &'a [i64];
198 type IntoIter = CellIter<'a>;
199
200 fn into_iter(self) -> Self::IntoIter {
201 self.iter()
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn push_and_iterate() {
211 let mut cells = CellArray::new();
212 cells.push_cell(&[0, 1, 2]);
213 cells.push_cell(&[2, 3, 4, 5]);
214 assert_eq!(cells.num_cells(), 2);
215 assert_eq!(cells.cell(0), &[0, 1, 2]);
216 assert_eq!(cells.cell(1), &[2, 3, 4, 5]);
217
218 let collected: Vec<&[i64]> = cells.iter().collect();
219 assert_eq!(collected.len(), 2);
220 }
221
222 #[test]
223 fn empty_cell_array() {
224 let cells = CellArray::new();
225 assert!(cells.is_empty());
226 assert_eq!(cells.num_cells(), 0);
227 assert_eq!(cells.iter().count(), 0);
228 }
229
230 #[test]
231 fn from_raw() {
232 let cells = CellArray::from_raw(vec![0, 3, 7], vec![0, 1, 2, 3, 4, 5, 6]);
233 assert_eq!(cells.num_cells(), 2);
234 assert_eq!(cells.cell(0), &[0, 1, 2]);
235 assert_eq!(cells.cell(1), &[3, 4, 5, 6]);
236 }
237
238 #[test]
239 fn cell_sizes() {
240 let mut cells = CellArray::new();
241 cells.push_cell(&[0, 1, 2]);
242 cells.push_cell(&[2, 3, 4, 5]);
243 assert_eq!(cells.cell_size(0), 3);
244 assert_eq!(cells.cell_size(1), 4);
245 assert_eq!(cells.max_cell_size(), 4);
246 let sizes: Vec<usize> = cells.cell_sizes().collect();
247 assert_eq!(sizes, vec![3, 4]);
248 }
249
250 #[test]
251 fn homogeneous() {
252 let mut tris = CellArray::new();
253 tris.push_cell(&[0, 1, 2]);
254 tris.push_cell(&[3, 4, 5]);
255 assert_eq!(tris.is_homogeneous(), Some(3));
256
257 let mut mixed = CellArray::new();
258 mixed.push_cell(&[0, 1, 2]);
259 mixed.push_cell(&[0, 1, 2, 3]);
260 assert_eq!(mixed.is_homogeneous(), None);
261 }
262
263 #[test]
264 fn into_iterator() {
265 let mut cells = CellArray::new();
266 cells.push_cell(&[0, 1]);
267 cells.push_cell(&[2, 3]);
268 let mut count = 0;
269 for _cell in &cells {
270 count += 1;
271 }
272 assert_eq!(count, 2);
273 }
274
275 #[test]
276 fn from_triangles() {
277 let cells = CellArray::from_triangles(&[[0, 1, 2], [3, 4, 5]]);
278 assert_eq!(cells.num_cells(), 2);
279 assert_eq!(cells.cell(0), &[0, 1, 2]);
280 assert_eq!(cells.is_homogeneous(), Some(3));
281 }
282
283 #[test]
284 fn from_quads() {
285 let cells = CellArray::from_quads(&[[0, 1, 2, 3]]);
286 assert_eq!(cells.num_cells(), 1);
287 assert_eq!(cells.cell(0).len(), 4);
288 }
289}