baby_shark/voxel/volume/
mod.rs

1pub mod builder;
2
3use self::fast_sweep::FastSweeping;
4use self::visitors::ValueMutVisitor;
5use crate::voxel::*;
6use crate::{dynamic_vdb, helpers::aliases::Vec3f};
7
8pub(super) type VolumeGrid = dynamic_vdb!(f32, par 5, 4, 3);
9
10#[derive(Debug)]
11pub struct Volume {
12    grid: Box<VolumeGrid>,
13    voxel_size: f32,
14}
15
16impl Volume {
17    /// Creates empty volume with given voxel size.
18    #[inline]
19    pub fn with_voxel_size(voxel_size: f32) -> Self {
20        Self {
21            voxel_size,
22            grid: VolumeGrid::empty(Vec3i::zeros()),
23        }
24    }
25
26    #[inline]
27    pub(super) fn new(grid: Box<VolumeGrid>, voxel_size: f32) -> Self {
28        Self { grid, voxel_size }
29    }
30
31    #[inline]
32    pub fn voxel_size(&self) -> f32 {
33        self.voxel_size
34    }
35
36    ///
37    /// Creates new SDF grid by evaluating given function on each grid point.
38    /// Inside is negative.
39    ///
40    pub fn from_fn<TFn: Fn(&Vec3f) -> f32>(
41        voxel_size: f32,
42        min: Vec3f,
43        max: Vec3f,
44        narrow_band_width: usize,
45        func: TFn,
46    ) -> Self {
47        let mut grid = VolumeGrid::empty(Vec3i::zeros());
48
49        let narrow_band_width = (narrow_band_width + 1) as f32 * voxel_size;
50        let min = (min / voxel_size).map(|x| x.floor() as isize);
51        let max = (max / voxel_size).map(|x| x.ceil() as isize);
52
53        for x in min.x..=max.x {
54            for y in min.y..=max.y {
55                for z in min.z..=max.z {
56                    let idx = Vec3i::new(x, y, z);
57                    let grid_point = idx.cast() * voxel_size;
58                    let value = func(&grid_point);
59
60                    if value.abs() > narrow_band_width {
61                        continue;
62                    }
63
64                    grid.insert(&idx, value);
65                }
66            }
67        }
68
69        // TODO: prune
70
71        Self { grid, voxel_size }
72    }
73
74    pub fn union(mut self, mut other: Self) -> Self {
75        self.grid.flood_fill();
76        other.grid.flood_fill();
77        self.grid.union(other.grid);
78        self
79    }
80
81    pub fn intersect(mut self, mut other: Self) -> Self {
82        self.grid.flood_fill();
83        other.grid.flood_fill();
84        self.grid.intersect(other.grid);
85        self
86    }
87
88    pub fn subtract(mut self, mut other: Self) -> Self {
89        self.grid.flood_fill();
90        other.grid.flood_fill();
91        self.grid.subtract(other.grid);
92        self
93    }
94
95    pub fn offset(mut self, distance: f32) -> Self {
96        self.grid.remove_if(|val| val.abs() > self.voxel_size * 2.0);
97
98        let mut extension_distance = distance.abs() + self.voxel_size + self.voxel_size;
99        extension_distance.set_sign(distance.sign());
100
101        let mut sweep = FastSweeping::new(self.voxel_size, extension_distance);
102        sweep.fast_sweep(self.grid.as_mut());
103
104        let mut offset = ValueMutVisitor::<VolumeGrid, _>::from_fn(|v| *v -= distance);
105        self.grid.visit_values_mut(&mut offset);
106
107        self
108    }
109
110    pub(in crate::voxel) fn grid(&self) -> &VolumeGrid {
111        // HIDE
112        &self.grid
113    }
114}
115
116impl Clone for Volume {
117    fn clone(&self) -> Self {
118        Self {
119            grid: self.grid.clone(),
120            voxel_size: self.voxel_size,
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use crate::{
128        io::*,
129        mesh::polygon_soup::data_structure::PolygonSoup,
130        voxel::{meshing::MarchingCubesMesher, prelude::MeshToVolume},
131    };
132    use std::path::Path;
133
134    #[test]
135    fn test_volume_offset() {
136        let mut reader = StlReader::new();
137        let mesh: PolygonSoup<f32> = reader
138            .read_from_file(Path::new("./assets/box2.stl"))
139            .expect("Read mesh");
140
141        let volume = MeshToVolume::default()
142            .with_voxel_size(0.2)
143            .convert(&mesh)
144            .unwrap()
145            .offset(0.5);
146
147        let vertices: Vec<_> = MarchingCubesMesher::default()
148            .with_voxel_size(volume.voxel_size())
149            .mesh(&volume);
150
151        assert_eq!(vertices.len(), 7944);
152    }
153}