|
16 | 16 | //! - `From<T> for UnstructuredGridPiece` implementations for the basic mesh types |
17 | 17 | //! - `Into<DataSet>` implementations for the basic mesh types |
18 | 18 |
|
19 | | -use crate::{new_map, Real}; |
| 19 | +use crate::{new_map, Aabb3d, MapType, Real}; |
20 | 20 | use bytemuck_derive::{Pod, Zeroable}; |
21 | 21 | use nalgebra::{Unit, Vector3}; |
22 | 22 | use rayon::prelude::*; |
@@ -223,6 +223,89 @@ impl<R: Real> TriMesh3d<R> { |
223 | 223 | } |
224 | 224 | } |
225 | 225 |
|
| 226 | + /// Returns a new triangle mesh containing only the specified triangles and removes all unreferenced vertices |
| 227 | + pub fn keep_tris(&self, cell_indices: &[usize]) -> Self { |
| 228 | + // Each entry is true if this vertex should be kept, false otherwise |
| 229 | + let vertex_keep_table = { |
| 230 | + let mut table = vec![false; self.vertices.len()]; |
| 231 | + for &cell_index in cell_indices { |
| 232 | + let cell_connectivity = &self.triangles[cell_index]; |
| 233 | + |
| 234 | + for &vertex_index in cell_connectivity { |
| 235 | + table[vertex_index] = true; |
| 236 | + } |
| 237 | + } |
| 238 | + table |
| 239 | + }; |
| 240 | + |
| 241 | + let old_to_new_label_map = { |
| 242 | + let mut label_map = MapType::default(); |
| 243 | + let mut next_label = 0; |
| 244 | + for (i, keep) in vertex_keep_table.iter().enumerate() { |
| 245 | + if *keep { |
| 246 | + label_map.insert(i, next_label); |
| 247 | + next_label += 1; |
| 248 | + } |
| 249 | + } |
| 250 | + label_map |
| 251 | + }; |
| 252 | + |
| 253 | + let relabeled_cells: Vec<_> = cell_indices |
| 254 | + .iter() |
| 255 | + .map(|&i| self.triangles[i].clone()) |
| 256 | + .map(|mut cell| { |
| 257 | + for index in &mut cell { |
| 258 | + *index = *old_to_new_label_map |
| 259 | + .get(index) |
| 260 | + .expect("Index must be in map"); |
| 261 | + } |
| 262 | + cell |
| 263 | + }) |
| 264 | + .collect(); |
| 265 | + |
| 266 | + let relabeled_vertices: Vec<_> = vertex_keep_table |
| 267 | + .iter() |
| 268 | + .enumerate() |
| 269 | + .filter_map(|(i, should_keep)| if *should_keep { Some(i) } else { None }) |
| 270 | + .map(|index| self.vertices[index].clone()) |
| 271 | + .collect(); |
| 272 | + |
| 273 | + Self { |
| 274 | + vertices: relabeled_vertices, |
| 275 | + triangles: relabeled_cells, |
| 276 | + } |
| 277 | + } |
| 278 | + |
| 279 | + /// Removes all triangles from the mesh that are completely outside of the given AABB and clamps the remaining triangles to the boundary |
| 280 | + pub fn clamp_with_aabb(&mut self, aabb: &Aabb3d<R>) { |
| 281 | + // Find all triangles with at least one vertex inside of AABB |
| 282 | + let triangles_to_keep = self |
| 283 | + .triangles |
| 284 | + .par_iter() |
| 285 | + .enumerate() |
| 286 | + .filter(|(_, tri)| tri.iter().any(|&v| aabb.contains_point(&self.vertices[v]))) |
| 287 | + .map(|(i, _)| i) |
| 288 | + .collect::<Vec<_>>(); |
| 289 | + // Remove all other triangles from mesh |
| 290 | + let new_mesh = self.keep_tris(&triangles_to_keep); |
| 291 | + // Replace current mesh |
| 292 | + let TriMesh3d { |
| 293 | + vertices, |
| 294 | + triangles, |
| 295 | + } = new_mesh; |
| 296 | + self.vertices = vertices; |
| 297 | + self.triangles = triangles; |
| 298 | + |
| 299 | + // Clamp remaining vertices to AABB |
| 300 | + self.vertices.par_iter_mut().for_each(|v| { |
| 301 | + let min = aabb.min(); |
| 302 | + let max = aabb.max(); |
| 303 | + v.x = v.x.clamp(min.x, max.x); |
| 304 | + v.y = v.y.clamp(min.y, max.y); |
| 305 | + v.z = v.z.clamp(min.z, max.z); |
| 306 | + }) |
| 307 | + } |
| 308 | + |
226 | 309 | /// Same as [`Self::vertex_normal_directions_inplace`] but assumes that the output is already zeroed |
227 | 310 | fn vertex_normal_directions_inplace_assume_zeroed(&self, normal_directions: &mut [Vector3<R>]) { |
228 | 311 | assert_eq!(normal_directions.len(), self.vertices.len()); |
|
0 commit comments