conspire/geometry/mesh/tessellation/base/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 geometry::{
6 Coordinates,
7 bvh::BoundingVolumeHierarchy,
8 mesh::{
9 Connectivity, Mesh,
10 smooth::Smoothing,
11 tessellation::{D, Normals, Tessellation},
12 },
13 },
14 math::{Scalar, Tensor, TensorVec},
15};
16use std::{array::from_fn, cell::OnceCell, collections::HashMap};
17
18const WELD_TOLERANCE: Scalar = 1e-6;
19
20impl Tessellation {
21 pub fn mesh(&self) -> &Mesh<D> {
22 &self.mesh
23 }
24 pub fn normals(&self) -> &Normals {
25 &self.normals
26 }
27 pub fn bvh(&self) -> &BoundingVolumeHierarchy<D> {
28 self.bvh
29 .get_or_init(|| BoundingVolumeHierarchy::from(&self.mesh))
30 }
31 pub fn smooth(&mut self, smoothing: Smoothing) {
32 self.mesh.smooth(smoothing);
33 self.refresh();
34 }
35 pub fn smooth_welded(&mut self, smoothing: Smoothing) {
36 let mut min = [f64::INFINITY; D];
37 let mut max = [f64::NEG_INFINITY; D];
38 for point in self.mesh.coordinates() {
39 (0..D).for_each(|axis| {
40 min[axis] = min[axis].min(point[axis]);
41 max[axis] = max[axis].max(point[axis]);
42 });
43 }
44 let diagonal = (0..D)
45 .map(|axis| (max[axis] - min[axis]).powi(2))
46 .sum::<f64>()
47 .sqrt();
48 self.smooth_welded_with_tolerance(smoothing, WELD_TOLERANCE * diagonal);
49 }
50 pub(crate) fn smooth_welded_with_tolerance(&mut self, smoothing: Smoothing, tolerance: f64) {
51 let mut representatives = Vec::with_capacity(self.mesh.number_of_nodes());
52 let mut anchors: HashMap<[i64; D], Vec<usize>> = HashMap::new();
53 let mut welded = Coordinates::new();
54 for point in self.mesh.coordinates() {
55 let cell = from_fn(|axis| (point[axis] / tolerance).floor() as i64);
56 let mut representative = None;
57 'search: for dz in -1i64..=1 {
58 for dy in -1i64..=1 {
59 for dx in -1i64..=1 {
60 if let Some(indices) =
61 anchors.get(&[cell[0] + dx, cell[1] + dy, cell[2] + dz])
62 {
63 for &index in indices {
64 if (point - &welded[index]).norm() <= tolerance {
65 representative = Some(index);
66 break 'search;
67 }
68 }
69 }
70 }
71 }
72 }
73 representatives.push(representative.unwrap_or_else(|| {
74 let index = welded.len();
75 welded.push(point.clone());
76 anchors.entry(cell).or_default().push(index);
77 index
78 }));
79 }
80 let triangles = match &self.mesh.connectivities()[0] {
81 Connectivity::Triangular(triangles) => triangles
82 .iter()
83 .map(|&[a, b, c]| [representatives[a], representatives[b], representatives[c]])
84 .collect::<Vec<_>>(),
85 _ => panic!(),
86 };
87 let mut mesh = Mesh::from((vec![Connectivity::Triangular(triangles.into())], welded));
88 mesh.smooth(smoothing);
89 let smoothed = mesh.coordinates();
90 self.mesh
91 .coordinates
92 .iter_mut()
93 .zip(&representatives)
94 .for_each(|(point, &representative)| *point = smoothed[representative].clone());
95 self.refresh();
96 }
97 fn refresh(&mut self) {
98 self.normals = self.mesh.normals();
99 self.bvh = OnceCell::new();
100 }
101}