1#[allow(unused_imports)]
6use super::functions::*;
7#[allow(unused_imports)]
8use super::functions_2::*;
9use rayon::prelude::*;
10
11#[derive(Debug, Clone)]
13pub enum SdfCombine {
14 Union(SdfShape, SdfShape),
16 Intersection(SdfShape, SdfShape),
18 Subtraction(SdfShape, SdfShape),
20 SmoothUnion(SdfShape, SdfShape, f64),
22}
23impl SdfCombine {
24 pub fn signed_distance(&self, p: [f64; 3]) -> f64 {
26 match self {
27 SdfCombine::Union(a, b) => a.signed_distance(p).min(b.signed_distance(p)),
28 SdfCombine::Intersection(a, b) => a.signed_distance(p).max(b.signed_distance(p)),
29 SdfCombine::Subtraction(a, b) => a.signed_distance(p).max(-b.signed_distance(p)),
30 SdfCombine::SmoothUnion(a, b, k) => {
31 let da = a.signed_distance(p);
32 let db = b.signed_distance(p);
33 let h = (0.5 + 0.5 * (db - da) / k).clamp(0.0, 1.0);
34 db * (1.0 - h) + da * h - k * h * (1.0 - h)
35 }
36 }
37 }
38}
39#[derive(Debug, Clone)]
41pub enum SdfShape {
42 Sphere {
44 center: [f64; 3],
46 r: f64,
48 },
49 Box3 {
51 center: [f64; 3],
53 half: [f64; 3],
55 },
56 Capsule {
58 a: [f64; 3],
60 b: [f64; 3],
62 r: f64,
64 },
65}
66impl SdfShape {
67 pub fn signed_distance(&self, p: [f64; 3]) -> f64 {
71 match self {
72 SdfShape::Sphere { center, r } => {
73 let dx = p[0] - center[0];
74 let dy = p[1] - center[1];
75 let dz = p[2] - center[2];
76 (dx * dx + dy * dy + dz * dz).sqrt() - r
77 }
78 SdfShape::Box3 { center, half } => {
79 let qx = (p[0] - center[0]).abs() - half[0];
80 let qy = (p[1] - center[1]).abs() - half[1];
81 let qz = (p[2] - center[2]).abs() - half[2];
82 let ext = (qx.max(0.0).powi(2) + qy.max(0.0).powi(2) + qz.max(0.0).powi(2)).sqrt();
83 let interior = qx.max(qy).max(qz).min(0.0);
84 ext + interior
85 }
86 SdfShape::Capsule { a, b, r } => {
87 let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
88 let ap = [p[0] - a[0], p[1] - a[1], p[2] - a[2]];
89 let ab_len2 = ab[0] * ab[0] + ab[1] * ab[1] + ab[2] * ab[2];
90 let t = if ab_len2 < 1e-12 {
91 0.0
92 } else {
93 ((ap[0] * ab[0] + ap[1] * ab[1] + ap[2] * ab[2]) / ab_len2).clamp(0.0, 1.0)
94 };
95 let closest = [a[0] + t * ab[0], a[1] + t * ab[1], a[2] + t * ab[2]];
96 let dx = p[0] - closest[0];
97 let dy = p[1] - closest[1];
98 let dz = p[2] - closest[2];
99 (dx * dx + dy * dy + dz * dz).sqrt() - r
100 }
101 }
102 }
103}
104#[derive(Debug, Clone)]
108pub struct GpuSdfGrid {
109 pub data: Vec<f64>,
111 pub nx: usize,
113 pub ny: usize,
115 pub nz: usize,
117 pub origin: [f64; 3],
119 pub cell_size: f64,
121}
122impl GpuSdfGrid {
123 pub fn new(nx: usize, ny: usize, nz: usize, origin: [f64; 3], cell_size: f64) -> Self {
125 Self {
126 data: vec![0.0_f64; nx * ny * nz],
127 nx,
128 ny,
129 nz,
130 origin,
131 cell_size,
132 }
133 }
134 #[inline]
136 pub fn index(&self, ix: usize, iy: usize, iz: usize) -> usize {
137 ix * self.ny * self.nz + iy * self.nz + iz
138 }
139 #[inline]
141 pub fn get(&self, ix: usize, iy: usize, iz: usize) -> f64 {
142 self.data[self.index(ix, iy, iz)]
143 }
144 #[inline]
146 pub fn cell_center(&self, ix: usize, iy: usize, iz: usize) -> [f64; 3] {
147 [
148 self.origin[0] + (ix as f64 + 0.5) * self.cell_size,
149 self.origin[1] + (iy as f64 + 0.5) * self.cell_size,
150 self.origin[2] + (iz as f64 + 0.5) * self.cell_size,
151 ]
152 }
153 pub fn sample_trilinear(&self, p: [f64; 3]) -> f64 {
157 let fx = (p[0] - self.origin[0]) / self.cell_size - 0.5;
158 let fy = (p[1] - self.origin[1]) / self.cell_size - 0.5;
159 let fz = (p[2] - self.origin[2]) / self.cell_size - 0.5;
160 let ix = fx.floor().clamp(0.0, (self.nx - 1) as f64) as usize;
161 let iy = fy.floor().clamp(0.0, (self.ny - 1) as f64) as usize;
162 let iz = fz.floor().clamp(0.0, (self.nz - 1) as f64) as usize;
163 let tx = (fx - ix as f64).clamp(0.0, 1.0);
164 let ty = (fy - iy as f64).clamp(0.0, 1.0);
165 let tz = (fz - iz as f64).clamp(0.0, 1.0);
166 let nx1 = (ix + 1).min(self.nx - 1);
167 let ny1 = (iy + 1).min(self.ny - 1);
168 let nz1 = (iz + 1).min(self.nz - 1);
169 let c000 = self.get(ix, iy, iz);
170 let c100 = self.get(nx1, iy, iz);
171 let c010 = self.get(ix, ny1, iz);
172 let c110 = self.get(nx1, ny1, iz);
173 let c001 = self.get(ix, iy, nz1);
174 let c101 = self.get(nx1, iy, nz1);
175 let c011 = self.get(ix, ny1, nz1);
176 let c111 = self.get(nx1, ny1, nz1);
177 let c00 = c000 * (1.0 - tx) + c100 * tx;
178 let c10 = c010 * (1.0 - tx) + c110 * tx;
179 let c01 = c001 * (1.0 - tx) + c101 * tx;
180 let c11 = c011 * (1.0 - tx) + c111 * tx;
181 let c0 = c00 * (1.0 - ty) + c10 * ty;
182 let c1 = c01 * (1.0 - ty) + c11 * ty;
183 c0 * (1.0 - tz) + c1 * tz
184 }
185 pub fn gradient_at(&self, p: [f64; 3]) -> [f64; 3] {
189 let h = self.cell_size * 0.5;
190 let gx = (self.sample_trilinear([p[0] + h, p[1], p[2]])
191 - self.sample_trilinear([p[0] - h, p[1], p[2]]))
192 / (2.0 * h);
193 let gy = (self.sample_trilinear([p[0], p[1] + h, p[2]])
194 - self.sample_trilinear([p[0], p[1] - h, p[2]]))
195 / (2.0 * h);
196 let gz = (self.sample_trilinear([p[0], p[1], p[2] + h])
197 - self.sample_trilinear([p[0], p[1], p[2] - h]))
198 / (2.0 * h);
199 [gx, gy, gz]
200 }
201}
202pub struct SphereTraceResult {
204 pub hit: bool,
206 pub position: [f64; 3],
208 pub t: f64,
210 pub iterations: usize,
212}
213pub struct SdfGrid {
215 pub nx: usize,
217 pub ny: usize,
219 pub nz: usize,
221 pub dx: f64,
223 pub origin: [f64; 3],
225 pub values: Vec<f64>,
227}
228impl SdfGrid {
229 pub fn new(nx: usize, ny: usize, nz: usize, dx: f64, origin: [f64; 3]) -> Self {
231 let n = nx * ny * nz;
232 Self {
233 nx,
234 ny,
235 nz,
236 dx,
237 origin,
238 values: vec![f64::MAX; n],
239 }
240 }
241 #[inline]
243 pub fn index(&self, i: usize, j: usize, k: usize) -> usize {
244 i * self.ny * self.nz + j * self.nz + k
245 }
246 #[inline]
248 pub fn world_pos(&self, i: usize, j: usize, k: usize) -> [f64; 3] {
249 [
250 self.origin[0] + (i as f64 + 0.5) * self.dx,
251 self.origin[1] + (j as f64 + 0.5) * self.dx,
252 self.origin[2] + (k as f64 + 0.5) * self.dx,
253 ]
254 }
255 #[inline]
257 pub fn get(&self, i: usize, j: usize, k: usize) -> f64 {
258 self.values[self.index(i, j, k)]
259 }
260 #[inline]
262 pub fn set(&mut self, i: usize, j: usize, k: usize, v: f64) {
263 let idx = self.index(i, j, k);
264 self.values[idx] = v;
265 }
266 pub fn compute_sphere_sdf(&mut self, center: [f64; 3], radius: f64) {
268 let _nx = self.nx;
269 let ny = self.ny;
270 let nz = self.nz;
271 let dx = self.dx;
272 let origin = self.origin;
273 self.values.par_iter_mut().enumerate().for_each(|(idx, v)| {
274 let i = idx / (ny * nz);
275 let j = (idx / nz) % ny;
276 let k = idx % nz;
277 let px = origin[0] + (i as f64 + 0.5) * dx;
278 let py = origin[1] + (j as f64 + 0.5) * dx;
279 let pz = origin[2] + (k as f64 + 0.5) * dx;
280 let dist =
281 ((px - center[0]).powi(2) + (py - center[1]).powi(2) + (pz - center[2]).powi(2))
282 .sqrt();
283 *v = dist - radius;
284 });
285 }
286 pub fn compute_box_sdf(&mut self, box_center: [f64; 3], half_extents: [f64; 3]) {
288 let _nx = self.nx;
289 let ny = self.ny;
290 let nz = self.nz;
291 let dx = self.dx;
292 let origin = self.origin;
293 self.values.par_iter_mut().enumerate().for_each(|(idx, v)| {
294 let i = idx / (ny * nz);
295 let j = (idx / nz) % ny;
296 let k = idx % nz;
297 let px = origin[0] + (i as f64 + 0.5) * dx - box_center[0];
298 let py = origin[1] + (j as f64 + 0.5) * dx - box_center[1];
299 let pz = origin[2] + (k as f64 + 0.5) * dx - box_center[2];
300 let qx = px.abs() - half_extents[0];
301 let qy = py.abs() - half_extents[1];
302 let qz = pz.abs() - half_extents[2];
303 let ext = (qx.max(0.0).powi(2) + qy.max(0.0).powi(2) + qz.max(0.0).powi(2)).sqrt();
304 let interior = qx.max(qy).max(qz).min(0.0);
305 *v = ext + interior;
306 });
307 }
308 pub fn compute_cylinder_sdf(&mut self, center: [f64; 2], radius: f64, half_height: f64) {
311 let ny = self.ny;
312 let nz = self.nz;
313 let dx = self.dx;
314 let origin = self.origin;
315 self.values.par_iter_mut().enumerate().for_each(|(idx, v)| {
316 let i = idx / (ny * nz);
317 let j = (idx / nz) % ny;
318 let k = idx % nz;
319 let px = origin[0] + (i as f64 + 0.5) * dx - center[0];
320 let py = origin[1] + (j as f64 + 0.5) * dx - center[1];
321 let pz = origin[2] + (k as f64 + 0.5) * dx;
322 let r = (px * px + py * py).sqrt();
323 let d_radial = r - radius;
324 let d_axial = pz.abs() - half_height;
325 let ext = (d_radial.max(0.0).powi(2) + d_axial.max(0.0).powi(2)).sqrt();
326 let interior = d_radial.max(d_axial).min(0.0);
327 *v = ext + interior;
328 });
329 }
330 pub fn compute_torus_sdf(&mut self, center: [f64; 3], major_radius: f64, minor_radius: f64) {
333 let ny = self.ny;
334 let nz = self.nz;
335 let dx = self.dx;
336 let origin = self.origin;
337 self.values.par_iter_mut().enumerate().for_each(|(idx, v)| {
338 let i = idx / (ny * nz);
339 let j = (idx / nz) % ny;
340 let k = idx % nz;
341 let px = origin[0] + (i as f64 + 0.5) * dx - center[0];
342 let py = origin[1] + (j as f64 + 0.5) * dx - center[1];
343 let pz = origin[2] + (k as f64 + 0.5) * dx - center[2];
344 let q_x = (px * px + pz * pz).sqrt() - major_radius;
345 let dist = (q_x * q_x + py * py).sqrt() - minor_radius;
346 *v = dist;
347 });
348 }
349 pub fn gradient_at(&self, i: usize, j: usize, k: usize) -> [f64; 3] {
351 let two_dx = 2.0 * self.dx;
352 let gx = if i == 0 {
353 (self.get(i + 1, j, k) - self.get(i, j, k)) / self.dx
354 } else if i + 1 == self.nx {
355 (self.get(i, j, k) - self.get(i - 1, j, k)) / self.dx
356 } else {
357 (self.get(i + 1, j, k) - self.get(i - 1, j, k)) / two_dx
358 };
359 let gy = if j == 0 {
360 (self.get(i, j + 1, k) - self.get(i, j, k)) / self.dx
361 } else if j + 1 == self.ny {
362 (self.get(i, j, k) - self.get(i, j - 1, k)) / self.dx
363 } else {
364 (self.get(i, j + 1, k) - self.get(i, j - 1, k)) / two_dx
365 };
366 let gz = if k == 0 {
367 (self.get(i, j, k + 1) - self.get(i, j, k)) / self.dx
368 } else if k + 1 == self.nz {
369 (self.get(i, j, k) - self.get(i, j, k - 1)) / self.dx
370 } else {
371 (self.get(i, j, k + 1) - self.get(i, j, k - 1)) / two_dx
372 };
373 [gx, gy, gz]
374 }
375 #[inline]
377 pub fn total_cells(&self) -> usize {
378 self.nx * self.ny * self.nz
379 }
380 pub fn sample(&self, pos: [f64; 3]) -> Option<f64> {
384 let fx = (pos[0] - self.origin[0]) / self.dx - 0.5;
385 let fy = (pos[1] - self.origin[1]) / self.dx - 0.5;
386 let fz = (pos[2] - self.origin[2]) / self.dx - 0.5;
387 if fx < 0.0 || fy < 0.0 || fz < 0.0 {
388 return None;
389 }
390 let ix = fx as usize;
391 let iy = fy as usize;
392 let iz = fz as usize;
393 if ix + 1 >= self.nx || iy + 1 >= self.ny || iz + 1 >= self.nz {
394 return None;
395 }
396 let tx = fx - ix as f64;
397 let ty = fy - iy as f64;
398 let tz = fz - iz as f64;
399 let c000 = self.get(ix, iy, iz);
400 let c100 = self.get(ix + 1, iy, iz);
401 let c010 = self.get(ix, iy + 1, iz);
402 let c110 = self.get(ix + 1, iy + 1, iz);
403 let c001 = self.get(ix, iy, iz + 1);
404 let c101 = self.get(ix + 1, iy, iz + 1);
405 let c011 = self.get(ix, iy + 1, iz + 1);
406 let c111 = self.get(ix + 1, iy + 1, iz + 1);
407 let c00 = c000 * (1.0 - tx) + c100 * tx;
408 let c10 = c010 * (1.0 - tx) + c110 * tx;
409 let c01 = c001 * (1.0 - tx) + c101 * tx;
410 let c11 = c011 * (1.0 - tx) + c111 * tx;
411 let c0 = c00 * (1.0 - ty) + c10 * ty;
412 let c1 = c01 * (1.0 - ty) + c11 * ty;
413 Some(c0 * (1.0 - tz) + c1 * tz)
414 }
415 pub fn gradient_at_point(&self, pos: [f64; 3]) -> Option<[f64; 3]> {
418 let fx = (pos[0] - self.origin[0]) / self.dx - 0.5;
419 let fy = (pos[1] - self.origin[1]) / self.dx - 0.5;
420 let fz = (pos[2] - self.origin[2]) / self.dx - 0.5;
421 if fx < 0.0 || fy < 0.0 || fz < 0.0 {
422 return None;
423 }
424 let ix = fx as usize;
425 let iy = fy as usize;
426 let iz = fz as usize;
427 if ix + 1 >= self.nx || iy + 1 >= self.ny || iz + 1 >= self.nz {
428 return None;
429 }
430 let eps = self.dx * 0.5;
431 let gx = (self.sample([pos[0] + eps, pos[1], pos[2]]).unwrap_or(0.0)
432 - self.sample([pos[0] - eps, pos[1], pos[2]]).unwrap_or(0.0))
433 / (2.0 * eps);
434 let gy = (self.sample([pos[0], pos[1] + eps, pos[2]]).unwrap_or(0.0)
435 - self.sample([pos[0], pos[1] - eps, pos[2]]).unwrap_or(0.0))
436 / (2.0 * eps);
437 let gz = (self.sample([pos[0], pos[1], pos[2] + eps]).unwrap_or(0.0)
438 - self.sample([pos[0], pos[1], pos[2] - eps]).unwrap_or(0.0))
439 / (2.0 * eps);
440 Some([gx, gy, gz])
441 }
442}
443#[derive(Debug, Clone)]
445pub struct Triangle {
446 pub v: [[f64; 3]; 3],
448}
449#[derive(Debug, Clone)]
451pub struct DistanceQuery {
452 pub distance: f64,
454 pub normal: [f64; 3],
456 pub closest_point: [f64; 3],
458 pub is_inside: bool,
460}