conspire/geometry/grid/from/tessellation/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::geometry::{Coordinate, grid::Voxels, mesh::Tessellation};
5use std::{
6 array::from_fn,
7 thread::{available_parallelism, scope},
8};
9
10impl Voxels<usize> {
11 pub fn from_tessellation(tessellation: &Tessellation, size: f64) -> Self {
12 let mesh = tessellation.mesh();
13 let bvh = tessellation.bvh();
14 let elements: Vec<&[usize]> = mesh.connectivities().iter().flatten().collect();
15 let coordinates = mesh.coordinates();
16 let mut min = [f64::INFINITY; 3];
17 let mut max = [f64::NEG_INFINITY; 3];
18 for point in coordinates {
19 (0..3).for_each(|ax| {
20 min[ax] = min[ax].min(point[ax]);
21 max[ax] = max[ax].max(point[ax]);
22 });
23 }
24 let nel: [usize; 3] = from_fn(|ax| (((max[ax] - min[ax]) / size).ceil() as usize).max(1));
25 let [nx, ny, _] = nel;
26 let layer = nx * ny;
27 let mut data = vec![0usize; layer * nel[2]];
28 let direction = Coordinate::from([1.0, 0.01, 0.001]);
29 let threads = available_parallelism().map_or(1, |threads| threads.get());
30 let chunk_size = data.len().div_ceil(threads).max(1);
31 scope(|scope| {
32 let (elements, direction) = (&elements, &direction);
33 data.chunks_mut(chunk_size)
34 .enumerate()
35 .for_each(|(chunk, voxels)| {
36 let offset = chunk * chunk_size;
37 scope.spawn(move || {
38 voxels.iter_mut().enumerate().for_each(|(local, voxel)| {
39 let flat = offset + local;
40 let index = [flat % nx, flat / nx % ny, flat / layer];
41 let center = Coordinate::from(from_fn::<_, 3, _>(|ax| {
42 min[ax] + (index[ax] as f64 + 0.5) * size
43 }));
44 let ray = (center, direction.clone()).into();
45 if bvh.intersections(&ray, coordinates, elements) % 2 == 1 {
46 *voxel = 1;
47 }
48 });
49 });
50 });
51 });
52 Voxels::new(data, nel)
53 }
54}