1use fenris_traits::Real;
2use itertools::Itertools;
3use nalgebra::allocator::Allocator;
4use nalgebra::{DefaultAllocator, DimName, OPoint, Point3, Scalar, Vector3, U3};
5use numeric_literals::replace_float_literals;
6use serde::{Deserialize, Serialize};
7use std::cmp::{max, min};
8use std::collections::{BTreeMap, BTreeSet, HashMap};
9use std::error::Error;
10use std::fmt;
11use std::fmt::Display;
12use std::hash::Hash;
13
14use crate::{compute_polyhedron_volume_from_faces, ConvexPolygon3d, ConvexPolyhedron, HalfSpace, LineSegment3d};
16use fenris_nested_vec::NestedVec;
18
19#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20struct UndirectedEdge {
21 indices: [usize; 2],
23}
24
25impl UndirectedEdge {
26 pub fn new(a: usize, b: usize) -> Self {
27 Self {
28 indices: [min(a, b), max(a, b)],
29 }
30 }
31
32 pub fn indices(&self) -> &[usize; 2] {
33 &self.indices
34 }
35}
36
37#[derive(Debug)]
38pub struct PolyMeshFace<'a, T: Scalar, D: DimName>
39where
40 DefaultAllocator: Allocator<T, D>,
41{
42 all_vertices: &'a [OPoint<T, D>],
43 face_vertex_indices: &'a [usize],
44}
45
46impl<'a, T: Scalar> ConvexPolygon3d<'a, T> for PolyMeshFace<'a, T, U3> {
47 fn num_vertices(&self) -> usize {
48 self.face_vertex_indices.len()
49 }
50
51 fn get_vertex(&self, index: usize) -> Option<OPoint<T, U3>> {
52 let v = self
53 .all_vertices
54 .get(*self.face_vertex_indices.get(index)?)
55 .expect("Internal error: Vertex must always exist if the local index is valid.");
56 Some(v.clone())
57 }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
64#[serde(bound(serialize = "OPoint<T, D>: Serialize"))]
65#[serde(bound(deserialize = "OPoint<T, D>: Deserialize<'de>"))]
66pub struct PolyMesh<T, D>
67where
68 T: Scalar,
69 D: DimName,
70 DefaultAllocator: Allocator<T, D>,
71{
72 #[serde(bound(serialize = "<DefaultAllocator as Allocator<T, D>>::Buffer: Serialize"))]
73 #[serde(bound(deserialize = "<DefaultAllocator as Allocator<T, D>>::Buffer: Deserialize<'de>"))]
74 vertices: Vec<OPoint<T, D>>,
75 faces: NestedVec<usize>,
76 cells: NestedVec<usize>,
77}
78
79pub type PolyMesh3d<T> = PolyMesh<T, U3>;
80
81impl<T, D> PolyMesh<T, D>
82where
83 T: Scalar,
84 D: DimName,
85 DefaultAllocator: Allocator<T, D>,
86{
87 pub fn new_empty() -> Self {
89 Self::from_poly_data(vec![], NestedVec::new(), NestedVec::new())
90 }
91
92 pub fn from_poly_data(vertices: Vec<OPoint<T, D>>, faces: NestedVec<usize>, cells: NestedVec<usize>) -> Self {
93 let num_vertices = vertices.len();
94 let num_faces = faces.len();
95
96 if faces.iter_array_elements().any(|idx| *idx >= num_vertices) {
97 panic!("Vertex index out of bounds in faces description.")
98 }
99
100 if cells.iter_array_elements().any(|idx| *idx >= num_faces) {
101 panic!("Face index out of bounds in cells description.")
102 }
103
104 Self {
105 vertices,
106 faces: faces,
107 cells: cells,
108 }
109 }
110
111 pub fn vertices(&self) -> &[OPoint<T, D>] {
112 &self.vertices
113 }
114
115 pub fn vertices_mut(&mut self) -> &mut [OPoint<T, D>] {
116 &mut self.vertices
117 }
118
119 pub fn num_faces(&self) -> usize {
120 self.faces.len()
121 }
122
123 pub fn num_cells(&self) -> usize {
124 self.cells.len()
125 }
126
127 pub fn face_vertices<'a>(&'a self, face_idx: usize) -> impl 'a + Iterator<Item = &'a OPoint<T, D>> {
128 self.get_face_connectivity(face_idx)
129 .into_iter()
130 .flatten()
131 .map(move |vertex_idx| &self.vertices()[*vertex_idx])
132 }
133
134 pub fn face_connectivity_iter<'a>(&'a self) -> impl 'a + Iterator<Item = &'a [usize]> {
135 self.faces.iter()
136 }
137
138 pub fn cell_connectivity_iter<'a>(&'a self) -> impl 'a + Iterator<Item = &'a [usize]> {
139 self.cells.iter()
140 }
141
142 pub fn get_face_connectivity(&self, index: usize) -> Option<&[usize]> {
143 self.faces.get(index)
144 }
145
146 pub fn get_cell_connectivity(&self, index: usize) -> Option<&[usize]> {
147 self.cells.get(index)
148 }
149
150 pub fn get_face(&self, index: usize) -> Option<PolyMeshFace<T, D>> {
151 self.get_face_connectivity(index)
152 .map(|face_vertex_indices| PolyMeshFace {
153 all_vertices: &self.vertices,
154 face_vertex_indices,
155 })
156 }
157
158 pub fn compute_face_cell_connectivity(&self) -> NestedVec<usize> {
161 let mut connectivity = vec![Vec::new(); self.num_faces()];
165
166 for (cell_idx, cell) in self.cell_connectivity_iter().enumerate() {
167 for face_idx in cell {
168 connectivity[*face_idx].push(cell_idx);
169 }
170 }
171
172 let mut compact = NestedVec::new();
173 for face_cell_conn in connectivity {
174 compact.push(&face_cell_conn);
175 }
176
177 compact
178 }
179
180 pub fn dedup_faces(&mut self) {
185 let mut sorted_face_connectivity = NestedVec::new();
186 for face in self.face_connectivity_iter() {
187 sorted_face_connectivity.push(face);
188 sorted_face_connectivity.last_mut().unwrap().sort_unstable();
189 }
190
191 let mut new_faces = NestedVec::new();
192 let mut connectivity_map = HashMap::new();
193 let mut face_relabel = Vec::with_capacity(self.num_faces());
195 for i in 0..self.num_faces() {
196 let sorted_face_conn = sorted_face_connectivity.get(i).unwrap();
197 if let Some(new_face_index) = connectivity_map.get(sorted_face_conn) {
199 face_relabel.push(*new_face_index);
202 } else {
203 let new_index = new_faces.len();
206 connectivity_map.insert(sorted_face_conn, new_index);
207 new_faces.push(self.get_face_connectivity(i).unwrap());
208 face_relabel.push(new_index);
209 }
210 }
211
212 self.faces = new_faces;
213
214 for i in 0..self.num_cells() {
215 let cell = self.cells.get_mut(i).unwrap();
216
217 for face_idx in cell {
218 *face_idx = face_relabel[*face_idx];
219 }
220 }
221 }
222
223 pub fn find_boundary_faces(&self) -> Vec<usize> {
225 let mut face_occurences = vec![0; self.num_faces()];
226
227 for cell_faces in self.cell_connectivity_iter() {
228 for face in cell_faces {
229 face_occurences[*face] += 1;
230 }
231 }
232
233 face_occurences
234 .into_iter()
235 .enumerate()
236 .filter_map(|(face_idx, count)| if count <= 1 { Some(face_idx) } else { None })
237 .collect()
238 }
239
240 pub fn concatenate<'a>(meshes: impl IntoIterator<Item = &'a PolyMesh<T, D>>) -> Self {
245 let meshes = meshes.into_iter();
246 let mut vertices = Vec::new();
247 let mut faces = NestedVec::new();
248 let mut cells = NestedVec::new();
249
250 let mut vertex_offset = 0;
251 let mut face_offset = 0;
252
253 for mesh in meshes {
254 vertices.extend(mesh.vertices().iter().cloned());
255
256 for face_vertices in mesh.face_connectivity_iter() {
257 let mut new_face_vertices = faces.begin_array();
258 for vertex_idx in face_vertices {
259 new_face_vertices.push_single(vertex_idx + vertex_offset);
260 }
261 }
262
263 for cell_faces in mesh.cell_connectivity_iter() {
264 let mut new_cell_faces = cells.begin_array();
265 for face_idx in cell_faces {
266 new_cell_faces.push_single(face_idx + face_offset);
267 }
268 }
269
270 vertex_offset += mesh.vertices().len();
271 face_offset += mesh.num_faces();
272 }
273
274 Self::from_poly_data(vertices, faces, cells)
275 }
276}
277
278impl<T, D> PolyMesh<T, D>
279where
280 T: Real,
281 D: DimName,
282 DefaultAllocator: Allocator<T, D>,
283{
284 pub fn split_edges_n_times(&mut self, n_times: usize) {
286 for _ in 0..n_times {
287 self.split_edges()
288 }
289 }
290
291 #[replace_float_literals(T::from_f64(literal).unwrap())]
293 pub fn split_edges(&mut self) {
294 let vertex_offset = self.vertices.len();
295 let mut additional_vertices = Vec::new();
296 let mut new_faces = NestedVec::new();
297 let mut subdivided_edges = HashMap::new();
298
299 for face in self.faces.iter() {
300 let edges = face
301 .iter()
302 .copied()
303 .cycle()
304 .take(face.len() + 1)
305 .tuple_windows();
306 let mut new_face = new_faces.begin_array();
307 for (v1, v2) in edges {
308 let edge = [v1.min(v2), v1.max(v2)];
309 let v12 = *subdivided_edges.entry(edge).or_insert_with(|| {
310 let new_vertex_index = vertex_offset + additional_vertices.len();
311 let midpoint = OPoint::from((&self.vertices[v1].coords + &self.vertices[v2].coords) * 0.5);
312 additional_vertices.push(midpoint);
313 new_vertex_index
314 });
315 new_face.push_single(v1);
316 new_face.push_single(v12);
317 }
318 }
319
320 self.vertices.extend(additional_vertices);
321 self.faces = new_faces;
322 }
323}
324
325impl<T> PolyMesh3d<T>
326where
327 T: Scalar,
328{
329 pub fn triangulate(&self) -> Result<PolyMesh3d<T>, Box<dyn Error>> {
338 let mut triangulated_faces = NestedVec::new();
348 let mut face_map = NestedVec::new();
349
350 for face in self.face_connectivity_iter() {
351 if face.len() < 3 {
352 return Err(Box::from(
353 "Encountered face with less than 3 vertices,\
354 cannot triangulate.",
355 ));
356 }
357
358 let mut face_map_array = face_map.begin_array();
359 let (min_idx, _) = face
361 .iter()
362 .enumerate()
363 .min_by_key(|(_, v_idx)| *v_idx)
364 .unwrap();
365
366 for i in 0..face.len() - 2 {
367 let a = face[min_idx];
368 let b = face[(i + 1 + min_idx) % face.len()];
369 let c = face[(i + 2 + min_idx) % face.len()];
370 face_map_array.push_single(triangulated_faces.len());
371 triangulated_faces.push(&[a, b, c]);
372 }
373 }
374
375 let mut tetrahedral_cells = NestedVec::new();
376 for cell in self.cell_connectivity_iter() {
377 if cell.len() > 0 {
379 let v_idx = cell
381 .iter()
382 .flat_map(|face_idx| {
383 self.get_face_connectivity(*face_idx).expect(
384 "Logic error: Cell references face that \
385 does not exist.",
386 )
387 })
388 .min()
389 .expect("Cell is non-empty");
390
391 for original_face_idx in cell {
399 let original_face_vertices = self
400 .get_face_connectivity(*original_face_idx)
401 .expect("Logic error: Cell references face that does not exist.");
402
403 if !original_face_vertices.contains(v_idx) {
404 let triangulated_face_indices = face_map
405 .get(*original_face_idx)
406 .expect("Logic error: Cell references face that does not exist.");
407
408 for tri_face_idx in triangulated_face_indices {
409 let tri_face_vertices = triangulated_faces.get(*tri_face_idx).unwrap();
410 assert_eq!(tri_face_vertices.len(), 3);
411
412 let a = tri_face_vertices[0];
414 let b = tri_face_vertices[1];
415 let c = tri_face_vertices[2];
416 let v = *v_idx;
417
418 let abc_idx = *tri_face_idx;
421 let abv_idx = triangulated_faces.len();
422 let bcv_idx = abv_idx + 1;
423 let cav_idx = bcv_idx + 1;
424
425 triangulated_faces.push(&[a, b, v]);
429 triangulated_faces.push(&[b, c, v]);
430 triangulated_faces.push(&[c, a, v]);
431 tetrahedral_cells.push(&[abc_idx, abv_idx, bcv_idx, cav_idx]);
432 }
433 }
434 }
435 }
436 }
437
438 let mut new_poly_mesh =
439 PolyMesh::from_poly_data(self.vertices().to_vec(), triangulated_faces, tetrahedral_cells);
440 new_poly_mesh.dedup_faces();
441 Ok(new_poly_mesh)
442 }
443
444 pub fn keep_cells(&self, cell_indices: &[usize]) -> Self {
445 let keep_faces: BTreeSet<_> = cell_indices
447 .iter()
448 .flat_map(|cell_idx| {
449 self.get_cell_connectivity(*cell_idx)
450 .expect("All cell indices must be in bounds")
451 })
452 .copied()
453 .collect();
454
455 let keep_vertices: BTreeSet<_> = keep_faces
456 .iter()
457 .flat_map(|face_idx| self.get_face_connectivity(*face_idx).unwrap())
458 .copied()
459 .collect();
460
461 let faces_old_to_new_map: HashMap<_, _> = keep_faces
462 .iter()
463 .enumerate()
464 .map(|(new_idx, old_idx)| (old_idx, new_idx))
465 .collect();
466
467 let vertices_old_to_new_map: HashMap<_, _> = keep_vertices
468 .iter()
469 .enumerate()
470 .map(|(new_idx, old_idx)| (*old_idx, new_idx))
471 .collect();
472
473 let new_vertices = keep_vertices
474 .iter()
475 .map(|old_vertex_idx| self.vertices()[*old_vertex_idx].clone())
476 .collect();
477
478 let mut new_faces = NestedVec::new();
479 for old_face_idx in &keep_faces {
480 let old_face_vertices = self.get_face_connectivity(*old_face_idx).unwrap();
481 let mut new_face_vertices = new_faces.begin_array();
482
483 for old_vertex_idx in old_face_vertices {
484 let new_vertex_idx = vertices_old_to_new_map.get(old_vertex_idx).unwrap();
485 new_face_vertices.push_single(*new_vertex_idx);
486 }
487 }
488
489 let mut new_cells = NestedVec::new();
490 for old_cell_idx in cell_indices {
491 let old_cell_faces = self.get_cell_connectivity(*old_cell_idx).unwrap();
492 let mut new_cell_faces = new_cells.begin_array();
493
494 for old_face_idx in old_cell_faces {
495 let new_face_idx = faces_old_to_new_map.get(old_face_idx).unwrap();
496 new_cell_faces.push_single(*new_face_idx);
497 }
498 }
499
500 Self::from_poly_data(new_vertices, new_faces, new_cells)
501 }
502}
503
504fn mark_vertices<T: Real>(vertices: &[Point3<T>], half_space: &HalfSpace<T>) -> Vec<bool> {
509 vertices
510 .iter()
511 .map(|v| half_space.contains_point(v))
512 .collect()
513}
514
515#[derive(Copy, Clone, Debug, PartialEq, Eq)]
516pub enum Classification {
517 Inside,
518 Outside,
519 Cut,
520}
521
522fn is_intersection_vertex(vertex_edge_representation: &UndirectedEdge) -> bool {
535 let [a, b] = vertex_edge_representation.indices();
536 a != b
537}
538
539impl<T> PolyMesh3d<T>
540where
541 T: Real,
542{
543 pub fn translate(&mut self, translation: &Vector3<T>) {
544 for v in self.vertices_mut() {
545 *v += translation;
546 }
547 }
548
549 pub fn translated(mut self, translation: &Vector3<T>) -> Self {
550 self.translate(translation);
551 self
552 }
553
554 #[replace_float_literals(T::from_f64(literal).unwrap())]
555 pub fn compute_volume(&self) -> T {
556 let boundary_faces = self.find_boundary_faces();
557 let face_iter = boundary_faces
558 .iter()
559 .map(|face_idx| self.get_face(*face_idx).unwrap());
560
561 compute_polyhedron_volume_from_faces(face_iter)
562 }
563
564 pub fn intersect_convex_polyhedron<'a>(&self, polyhedron: &impl ConvexPolyhedron<'a, T>) -> Self {
565 let mut mesh = self.clone();
566 for i in 0..polyhedron.num_faces() {
567 let face = polyhedron.get_face(i).unwrap();
568 if let Some(plane) = face.compute_plane() {
569 let half_space = HalfSpace::from_plane(&plane.flipped());
570 mesh = mesh.intersect_half_space(&half_space);
571 }
572 }
573 mesh
574 }
575
576 pub fn intersect_half_space(&self, half_space: &HalfSpace<T>) -> Self {
577 let vertex_half_space_membership = mark_vertices(&self.vertices, half_space);
586
587 let mut new_faces = NestedVec::new();
588 let mut face_classifications = Vec::with_capacity(self.num_faces());
589
590 for face_vertices in self.faces.iter() {
591 let mut new_face_vertices = new_faces.begin_array();
592
593 let mut classification = Classification::Inside;
594
595 let face_vertices = face_vertices.iter().chain(face_vertices.first()).copied();
596 for (a, b) in face_vertices.tuple_windows() {
597 let a_is_inside = vertex_half_space_membership[a];
598 let b_is_inside = vertex_half_space_membership[b];
599
600 if a_is_inside {
601 new_face_vertices.push_single(UndirectedEdge::new(a, a));
602 }
603
604 if a_is_inside != b_is_inside {
605 new_face_vertices.push_single(UndirectedEdge::new(a, b));
607 classification = Classification::Cut;
608 }
609 }
610
611 if new_face_vertices.count() == 0 {
614 classification = Classification::Outside;
615 }
616
617 face_classifications.push(classification);
618 }
619
620 #[derive(Debug)]
621 struct IntersectionEdge {
622 a: UndirectedEdge,
624 b: UndirectedEdge,
625 }
626
627 let mut intersection_edges = Vec::new();
628
629 let mut new_cells = NestedVec::new();
630 for cell_faces in self.cells.iter() {
631 intersection_edges.clear();
632 let mut new_cell_faces = new_cells.begin_array();
633
634 for face_idx in cell_faces {
635 let face_classification = face_classifications[*face_idx];
636 match face_classification {
637 Classification::Inside => {
638 new_cell_faces.push_single(*face_idx);
639 }
640 Classification::Outside => {}
641 Classification::Cut => {
642 new_cell_faces.push_single(*face_idx);
643 let face_vertices = new_faces
644 .get(*face_idx)
645 .expect("Invalid face index referenced in cell.");
646 let face_vertices = face_vertices.iter().chain(face_vertices.first());
647 for (a, b) in face_vertices.tuple_windows() {
648 if is_intersection_vertex(a) && is_intersection_vertex(b) {
651 intersection_edges.push(IntersectionEdge {
652 a: *a,
654 b: *b,
655 });
656 }
657 }
658 }
659 }
660 }
661
662 while let Some(start_edge) = intersection_edges.pop() {
668 let new_face_index = new_faces.len();
674 let mut new_face_vertices = new_faces.begin_array();
675
676 new_face_vertices.push_single(start_edge.a);
677 let mut next_vertex = start_edge.b;
678
679 while let Some(next_local_idx) = intersection_edges
680 .iter()
681 .position(|edge| edge.a == next_vertex || edge.b == next_vertex)
682 {
683 let next_edge = intersection_edges.swap_remove(next_local_idx);
684 if next_edge.a == next_vertex {
685 new_face_vertices.push_single(next_edge.a);
686 next_vertex = next_edge.b;
687 } else {
688 new_face_vertices.push_single(next_edge.b);
689 next_vertex = next_edge.a;
690 }
691 }
692
693 new_cell_faces.push_single(new_face_index);
694 }
695 }
696
697 let vertex_label_map = generate_edge_repr_vertex_labels(
702 new_faces
703 .iter()
704 .flat_map(|face_vertices| face_vertices)
705 .copied(),
706 );
707
708 let mut final_vertices = vec![Point3::origin(); vertex_label_map.len()];
710 for (edge_rep, new_vertex_idx) in &vertex_label_map {
711 let [a, b] = *edge_rep.indices();
712 let vertex_coords = if a == b {
713 self.vertices[a]
714 } else {
715 let v_a = self.vertices[a];
716 let v_b = self.vertices[b];
717 let segment = LineSegment3d::from_end_points(v_a, v_b);
718 segment.closest_point_to_plane(&half_space.plane())
719 };
720 final_vertices[*new_vertex_idx] = vertex_coords;
721 }
722
723 let (final_faces, face_label_map) = relabel_face_edge_representations(&new_faces, &vertex_label_map);
726
727 let mut final_cells = NestedVec::new();
730 for cell_faces in new_cells.iter() {
731 if !cell_faces.is_empty() {
732 let mut new_cell_faces = final_cells.begin_array();
733 for cell_face in cell_faces {
734 new_cell_faces.push_single(
735 *face_label_map
736 .get(cell_face)
737 .expect("Logic error: Face index is not in map"),
738 );
739 }
740 }
741 }
742
743 PolyMesh3d::from_poly_data(final_vertices, final_faces, final_cells)
744 }
745}
746
747fn generate_edge_repr_vertex_labels(
748 vertices_in_edge_repr: impl IntoIterator<Item = UndirectedEdge>,
749) -> BTreeMap<UndirectedEdge, usize> {
750 let mut map = BTreeMap::new();
751 let mut iter = vertices_in_edge_repr.into_iter();
752
753 let mut next_available_index = 0;
754 while let Some(vertex) = iter.next() {
755 map.entry(vertex).or_insert_with(|| {
756 let idx = next_available_index;
757 next_available_index += 1;
758 idx
759 });
760 }
761
762 map
763}
764
765fn relabel_face_edge_representations(
771 faces: &NestedVec<UndirectedEdge>,
772 vertex_label_map: &BTreeMap<UndirectedEdge, usize>,
773) -> (NestedVec<usize>, HashMap<usize, usize>) {
774 let mut new_faces = NestedVec::new();
775 let mut face_label_map = HashMap::new();
776 let mut next_available_index = 0;
777 {
778 for (i, face_vertices) in faces.iter().enumerate() {
779 if !face_vertices.is_empty() {
780 let mut new_face_vertices = new_faces.begin_array();
781 for vertex_edge_rep in face_vertices {
782 new_face_vertices.push_single(
783 *vertex_label_map
784 .get(vertex_edge_rep)
785 .expect("Logic error: Label map must map all relevant vertices."),
786 );
787 }
788
789 face_label_map.insert(i, next_available_index);
790 next_available_index += 1;
791 }
792 }
793 }
794
795 (new_faces, face_label_map)
796}
797
798impl<T> Display for PolyMesh3d<T>
799where
800 T: Scalar + Display,
801{
802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
803 writeln!(f, "PolyMesh3d")?;
804 writeln!(f, " Vertices:")?;
805 for v in self.vertices() {
806 writeln!(f, " {}", v)?;
807 }
808 writeln!(f)?;
809
810 writeln!(f, " Face vertex indices:")?;
811 for (i, vertex_indices) in self.face_connectivity_iter().enumerate() {
812 write!(f, " {}: ", i)?;
813 if let Some(first) = vertex_indices.first() {
814 write!(f, "{}", first)?;
815 }
816 for idx in vertex_indices.iter().skip(1) {
817 write!(f, ", {}", idx)?;
818 }
819 writeln!(f)?;
820 }
821 writeln!(f)?;
822
823 writeln!(f, " Cell face indices:")?;
824 for (i, face_indices) in self.cell_connectivity_iter().enumerate() {
825 write!(f, " {}: ", i)?;
826 if let Some(first) = face_indices.first() {
827 write!(f, "{}", first)?;
828 }
829 for idx in face_indices.iter().skip(1) {
830 write!(f, ", {}", idx)?;
831 }
832 writeln!(f)?;
833 }
834
835 Ok(())
836 }
837}