1use macaw::Vec3;
2
3use crate::SignedDistance;
4
5pub type Index3 = [usize; 3];
8
9pub struct Grid3<T = f32> {
14 size: Index3,
15 data: Vec<T>,
16}
17
18impl<T> Grid3<T> {
19 pub fn data(&self) -> &[T] {
21 &self.data
22 }
23
24 pub fn size(&self) -> Index3 {
25 self.size
26 }
27}
28
29impl<T> std::ops::Index<Index3> for Grid3<T> {
30 type Output = T;
31
32 #[inline]
33 fn index(&self, p: Index3) -> &Self::Output {
34 debug_assert!(p[0] < self.size[0]);
35 debug_assert!(p[1] < self.size[1]);
36 debug_assert!(p[2] < self.size[2]);
37 &self.data[p[0] + self.size[0] * (p[1] + self.size[1] * p[2])]
38 }
39}
40
41impl<T> std::ops::IndexMut<Index3> for Grid3<T> {
42 #[inline]
43 fn index_mut(&mut self, p: Index3) -> &mut Self::Output {
44 debug_assert!(p[0] < self.size[0]);
45 debug_assert!(p[1] < self.size[1]);
46 debug_assert!(p[2] < self.size[2]);
47 &mut self.data[p[0] + self.size[0] * (p[1] + self.size[1] * p[2])]
48 }
49}
50
51impl<T: std::cmp::PartialEq> std::cmp::PartialEq for Grid3<T> {
52 fn eq(&self, other: &Self) -> bool {
53 self.size == other.size && self.data == other.data
54 }
55}
56
57impl<T: SignedDistance + Copy + Clone + Default> Grid3<T> {
58 pub fn new(size: Index3) -> Self {
59 Self {
60 size,
61 data: vec![T::default(); size[0] * size[1] * size[2]],
62 }
63 }
64
65 pub fn set(&mut self, mut f: impl FnMut(Index3) -> T) {
67 let mut index = 0;
68 for z in 0..self.size[2] {
69 for y in 0..self.size[1] {
70 for x in 0..self.size[0] {
71 self.data[index] = f([x, y, z]);
72 index += 1;
73 }
74 }
75 }
76 }
77}
78
79impl<T> Grid3<T>
80where
81 T: SignedDistance,
82{
83 #[inline]
86 pub fn gradient_clamped(&self, p: Index3) -> Vec3 {
87 let p = [
88 p[0].clamp(1, self.size[0] - 2),
89 p[1].clamp(1, self.size[1] - 2),
90 p[2].clamp(1, self.size[2] - 2),
91 ];
92 let dx = self[[p[0] + 1, p[1], p[2]]].distance() - self[[p[0] - 1, p[1], p[2]]].distance();
93 let dy = self[[p[0], p[1] + 1, p[2]]].distance() - self[[p[0], p[1] - 1, p[2]]].distance();
94 let dz = self[[p[0], p[1], p[2] + 1]].distance() - self[[p[0], p[1], p[2] - 1]].distance();
95 Vec3::new(dx, dy, dz) / 2.0
96 }
97
98 #[inline]
102 pub fn fast_gradient(
103 &self,
104 x: usize,
105 y: usize,
106 z: usize,
107 i: usize, ys: usize, zs: usize, ) -> Vec3 {
111 let sx = self.size[0];
112 let sy = self.size[1];
113 let sz = self.size[2];
114
115 let x1 = if x < sx - 1 { i + 1 } else { i };
116 let x2 = if x > 0 { i - 1 } else { i };
117 let y1 = if y < sy - 1 { i + ys } else { i };
118 let y2 = if y > 0 { i - ys } else { i };
119 let z1 = if z < sz - 1 { i + zs } else { i };
120 let z2 = if z > 0 { i - zs } else { i };
121
122 let dx = self.data[x1].distance() - self.data[x2].distance();
123 let dy = self.data[y1].distance() - self.data[y2].distance();
124 let dz = self.data[z1].distance() - self.data[z2].distance();
125
126 Vec3::new(dx, dy, dz) }
128
129 fn set_truncated_span(
130 x_slice: &mut [T],
131 y: usize,
132 z: usize,
133 sdf: impl Fn(Index3) -> T + Send + Sync,
134 truncate_dist: f32,
135 ) {
136 let w = x_slice.len();
137 let mut x = 0;
138
139 while x < w {
140 let distance = sdf([x, y, z]);
141 let abs_distance = distance.distance().abs();
142
143 x_slice[x] = distance;
144 x += 1;
145
146 let mut distance_bound = abs_distance - 1.0;
147 while distance_bound > truncate_dist && x < w {
148 x_slice[x] = distance;
149 x += 1;
150
151 distance_bound -= 1.0;
152 }
153 }
154 }
155
156 pub fn set_truncated_sync(
162 &mut self,
163 sdf: impl Fn(Index3) -> T + Send + Sync,
164 truncate_dist: f32,
165 ) {
166 let _d = self.size[2];
167 let h = self.size[1];
168 let w = self.size[0];
169
170 self.data
171 .chunks_mut(w * h)
172 .enumerate()
173 .for_each(|(z, xy_plane)| {
174 xy_plane.chunks_mut(w).enumerate().for_each(|(y, x_slice)| {
175 Self::set_truncated_span(x_slice, y, z, &sdf, truncate_dist);
176 });
177 });
178 }
179
180 #[cfg(not(feature = "with_rayon"))]
184 pub fn set_truncated(&mut self, sdf: impl Fn(Index3) -> T + Send + Sync, truncate_dist: f32) {
185 self.set_truncated_sync(sdf, truncate_dist);
186 }
187
188 #[cfg(feature = "with_rayon")]
192 pub fn set_truncated(&mut self, sdf: impl Fn(Index3) -> T + Send + Sync, truncate_dist: f32)
193 where
194 T: Send,
195 {
196 let _d = self.size[2];
197 let h = self.size[1];
198 let w = self.size[0];
199
200 use rayon::prelude::*;
201
202 self.data
203 .par_chunks_mut(w * h)
204 .enumerate()
205 .for_each(|(z, xy_plane)| {
206 xy_plane
207 .par_chunks_mut(w)
208 .enumerate()
209 .for_each(|(y, x_slice)| {
210 Self::set_truncated_span(x_slice, y, z, &sdf, truncate_dist);
211 });
212 });
213 }
214}
215
216