baby_shark/voxel/volume/
mod.rs1pub 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 #[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 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 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 &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}