1use super::functions::ImplicitSurface;
6#[allow(unused_imports)]
7use super::functions::*;
8#[allow(unused_imports)]
9use super::functions_2::*;
10
11pub struct SdfPlane {
13 pub normal: [f64; 3],
15 pub d: f64,
17}
18impl SdfPlane {
19 pub fn new(normal: [f64; 3], d: f64) -> Self {
21 Self {
22 normal: normalize(normal),
23 d,
24 }
25 }
26}
27pub struct CsgSmoothDifference {
31 pub a: Box<dyn ImplicitSurface>,
33 pub b: Box<dyn ImplicitSurface>,
35 pub k: f64,
37}
38impl CsgSmoothDifference {
39 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>, k: f64) -> Self {
41 Self { a, b, k }
42 }
43}
44pub struct SdfCone {
48 pub apex: [f64; 3],
50 pub half_angle: f64,
52 pub height: f64,
54}
55impl SdfCone {
56 pub fn new(apex: [f64; 3], half_angle: f64, height: f64) -> Self {
58 Self {
59 apex,
60 half_angle,
61 height,
62 }
63 }
64}
65pub struct SdfSphere {
67 pub center: [f64; 3],
69 pub radius: f64,
71}
72impl SdfSphere {
73 pub fn new(center: [f64; 3], radius: f64) -> Self {
75 Self { center, radius }
76 }
77}
78pub struct CsgIntersection {
82 pub a: Box<dyn ImplicitSurface>,
84 pub b: Box<dyn ImplicitSurface>,
86}
87impl CsgIntersection {
88 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>) -> Self {
90 Self { a, b }
91 }
92}
93pub enum CsgTree {
98 Leaf(Box<dyn ImplicitSurface>),
100 Node {
102 op: CsgOp,
104 left: Box<CsgTree>,
106 right: Box<CsgTree>,
108 },
109}
110impl CsgTree {
111 pub fn leaf(s: impl ImplicitSurface + 'static) -> Self {
113 CsgTree::Leaf(Box::new(s))
114 }
115 pub fn union(left: CsgTree, right: CsgTree) -> Self {
117 CsgTree::Node {
118 op: CsgOp::Union,
119 left: Box::new(left),
120 right: Box::new(right),
121 }
122 }
123 pub fn intersection(left: CsgTree, right: CsgTree) -> Self {
125 CsgTree::Node {
126 op: CsgOp::Intersection,
127 left: Box::new(left),
128 right: Box::new(right),
129 }
130 }
131 pub fn difference(left: CsgTree, right: CsgTree) -> Self {
133 CsgTree::Node {
134 op: CsgOp::Difference,
135 left: Box::new(left),
136 right: Box::new(right),
137 }
138 }
139}
140pub struct CsgUnion {
144 pub a: Box<dyn ImplicitSurface>,
146 pub b: Box<dyn ImplicitSurface>,
148}
149impl CsgUnion {
150 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>) -> Self {
152 Self { a, b }
153 }
154}
155pub struct SdfTorus {
157 pub major_radius: f64,
159 pub minor_radius: f64,
161}
162impl SdfTorus {
163 pub fn new(major_radius: f64, minor_radius: f64) -> Self {
165 Self {
166 major_radius,
167 minor_radius,
168 }
169 }
170}
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum CsgOp {
174 Union,
176 Intersection,
178 Difference,
180}
181pub struct SdfCapsule {
183 pub center: [f64; 3],
185 pub radius: f64,
187 pub half_height: f64,
189}
190impl SdfCapsule {
191 pub fn new(center: [f64; 3], radius: f64, half_height: f64) -> Self {
193 Self {
194 center,
195 radius,
196 half_height,
197 }
198 }
199}
200pub struct CsgOffsetSurface {
207 inner_sdf: Box<dyn Fn([f64; 3]) -> f64 + Send + Sync>,
209 pub offset: f64,
211}
212impl CsgOffsetSurface {
213 pub fn new(sdf: Box<dyn Fn([f64; 3]) -> f64 + Send + Sync>, offset: f64) -> Self {
215 Self {
216 inner_sdf: sdf,
217 offset,
218 }
219 }
220 pub fn eval(&self, p: [f64; 3]) -> f64 {
222 (self.inner_sdf)(p) - self.offset
223 }
224 pub fn finite_diff_gradient(&self, p: [f64; 3]) -> [f64; 3] {
226 const EPS: f64 = 1e-4;
227 [
228 (self.eval([p[0] + EPS, p[1], p[2]]) - self.eval([p[0] - EPS, p[1], p[2]]))
229 / (2.0 * EPS),
230 (self.eval([p[0], p[1] + EPS, p[2]]) - self.eval([p[0], p[1] - EPS, p[2]]))
231 / (2.0 * EPS),
232 (self.eval([p[0], p[1], p[2] + EPS]) - self.eval([p[0], p[1], p[2] - EPS]))
233 / (2.0 * EPS),
234 ]
235 }
236}
237impl ImplicitSurface for CsgOffsetSurface {
238 fn sdf(&self, p: [f64; 3]) -> f64 {
239 self.eval(p)
240 }
241 fn gradient(&self, p: [f64; 3]) -> [f64; 3] {
242 self.finite_diff_gradient(p)
243 }
244}
245#[derive(Debug, Clone)]
247pub struct MarchingCell {
248 pub min: [f64; 3],
250 pub step: f64,
252 pub corner_values: [f64; 8],
254}
255impl MarchingCell {
256 pub fn has_surface(&self) -> bool {
258 let has_inside = self.corner_values.iter().any(|&v| v < 0.0);
259 let has_outside = self.corner_values.iter().any(|&v| v >= 0.0);
260 has_inside && has_outside
261 }
262 fn edge_vertex(&self, i0: usize, i1: usize) -> [f64; 3] {
264 let offsets: [[f64; 3]; 8] = [
265 [0.0, 0.0, 0.0],
266 [self.step, 0.0, 0.0],
267 [self.step, self.step, 0.0],
268 [0.0, self.step, 0.0],
269 [0.0, 0.0, self.step],
270 [self.step, 0.0, self.step],
271 [self.step, self.step, self.step],
272 [0.0, self.step, self.step],
273 ];
274 let v0 = self.corner_values[i0];
275 let v1 = self.corner_values[i1];
276 let t = if (v1 - v0).abs() > 1e-14 {
277 v0 / (v0 - v1)
278 } else {
279 0.5
280 };
281 let p0 = add(self.min, offsets[i0]);
282 let p1 = add(self.min, offsets[i1]);
283 lerp3(p0, p1, t)
284 }
285 pub fn extract_vertices(&self) -> Vec<[f64; 3]> {
287 if !self.has_surface() {
288 return vec![];
289 }
290 let edges: [(usize, usize); 12] = [
291 (0, 1),
292 (1, 2),
293 (2, 3),
294 (3, 0),
295 (4, 5),
296 (5, 6),
297 (6, 7),
298 (7, 4),
299 (0, 4),
300 (1, 5),
301 (2, 6),
302 (3, 7),
303 ];
304 edges
305 .iter()
306 .filter_map(|&(i0, i1)| {
307 let v0 = self.corner_values[i0];
308 let v1 = self.corner_values[i1];
309 if v0.signum() != v1.signum() {
310 Some(self.edge_vertex(i0, i1))
311 } else {
312 None
313 }
314 })
315 .collect()
316 }
317}
318pub struct SdfBox {
320 pub center: [f64; 3],
322 pub half_extents: [f64; 3],
324}
325impl SdfBox {
326 pub fn new(center: [f64; 3], half_extents: [f64; 3]) -> Self {
328 Self {
329 center,
330 half_extents,
331 }
332 }
333}
334pub struct SdfCylinder {
336 pub center: [f64; 3],
338 pub radius: f64,
340}
341impl SdfCylinder {
342 pub fn new(center: [f64; 3], radius: f64) -> Self {
344 Self { center, radius }
345 }
346}
347pub struct CsgDifference {
351 pub a: Box<dyn ImplicitSurface>,
353 pub b: Box<dyn ImplicitSurface>,
355}
356impl CsgDifference {
357 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>) -> Self {
359 Self { a, b }
360 }
361}
362pub struct CsgSmoothUnion {
366 pub a: Box<dyn ImplicitSurface>,
368 pub b: Box<dyn ImplicitSurface>,
370 pub k: f64,
372}
373impl CsgSmoothUnion {
374 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>, k: f64) -> Self {
376 Self { a, b, k }
377 }
378}
379pub struct CsgSmoothIntersection {
383 pub a: Box<dyn ImplicitSurface>,
385 pub b: Box<dyn ImplicitSurface>,
387 pub k: f64,
389}
390impl CsgSmoothIntersection {
391 pub fn new(a: Box<dyn ImplicitSurface>, b: Box<dyn ImplicitSurface>, k: f64) -> Self {
393 Self { a, b, k }
394 }
395}
396#[derive(Debug, Clone, Copy, PartialEq)]
398pub enum PlaneSide {
399 Front,
401 Back,
403 OnPlane,
405}
406pub struct SdfCappedCylinder {
408 pub center: [f64; 3],
410 pub radius: f64,
412 pub half_height: f64,
414}
415impl SdfCappedCylinder {
416 pub fn new(center: [f64; 3], radius: f64, half_height: f64) -> Self {
418 Self {
419 center,
420 radius,
421 half_height,
422 }
423 }
424}
425pub struct SdfRoundedBox {
429 pub center: [f64; 3],
431 pub half_extents: [f64; 3],
433 pub radius: f64,
435}
436impl SdfRoundedBox {
437 pub fn new(center: [f64; 3], half_extents: [f64; 3], radius: f64) -> Self {
439 Self {
440 center,
441 half_extents,
442 radius,
443 }
444 }
445}
446
447#[cfg(test)]
448mod csg_offset_tests {
449 use super::super::functions::ImplicitSurface;
450 use super::CsgOffsetSurface;
451
452 fn unit_sphere_sdf(p: [f64; 3]) -> f64 {
453 (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt() - 1.0
454 }
455
456 #[test]
457 fn test_offset_sphere_eval_inside() {
458 let s = CsgOffsetSurface::new(Box::new(unit_sphere_sdf), 1.0);
459 assert!(s.eval([1.5, 0.0, 0.0]) < 0.0);
460 }
461
462 #[test]
463 fn test_offset_sphere_eval_outside() {
464 let s = CsgOffsetSurface::new(Box::new(unit_sphere_sdf), 1.0);
465 assert!(s.eval([3.5, 0.0, 0.0]) > 0.0);
466 }
467
468 #[test]
469 fn test_offset_sphere_on_surface() {
470 let s = CsgOffsetSurface::new(Box::new(unit_sphere_sdf), 1.0);
471 assert!(s.eval([2.0, 0.0, 0.0]).abs() < 1e-10);
472 }
473
474 #[test]
475 fn test_offset_sphere_gradient_outward() {
476 let s = CsgOffsetSurface::new(Box::new(unit_sphere_sdf), 1.0);
477 let g = s.finite_diff_gradient([2.0, 0.0, 0.0]);
478 assert!(g[0] > 0.5 && g[1].abs() < 0.01 && g[2].abs() < 0.01);
479 }
480
481 #[test]
482 fn test_implicit_surface_trait() {
483 let s = CsgOffsetSurface::new(Box::new(unit_sphere_sdf), 1.0);
484 let t: &dyn ImplicitSurface = &s;
485 assert!(t.sdf([2.5, 0.0, 0.0]) > 0.0);
486 assert!(t.sdf([1.5, 0.0, 0.0]) < 0.0);
487 }
488}