Skip to main content

sdfu/
mods.rs

1//! Modifiers for SDFs.
2use super::*;
3use crate::mathtypes::*;
4use std::ops::*;
5
6/// Make an SDF have rounded outside edges.
7#[derive(Clone, Copy, Debug)]
8pub struct Round<T, S> {
9    pub sdf: S,
10    pub radius: T,
11}
12
13impl<T, S> Round<T, S> {
14    pub fn new(sdf: S, radius: T) -> Self {
15        Round { sdf, radius }
16    }
17}
18
19impl<T, V, S> SDF<T, V> for Round<T, S>
20where
21    T: Copy + Sub<T, Output = T>,
22    V: Vec<T>,
23    S: SDF<T, V>,
24{
25    #[inline]
26    fn dist(&self, p: V) -> T {
27        self.sdf.dist(p) - self.radius
28    }
29}
30
31/// Elongate an SDF along a single axis. The elongation is
32/// symmetrical around the origin.
33#[derive(Clone, Copy, Debug)]
34pub struct Elongate<T, S, D> {
35    pub sdf: S,
36    pub axis: Axis,
37    pub elongation: T,
38    _pd: std::marker::PhantomData<D>,
39}
40
41impl<T, S, D> Elongate<T, S, D> {
42    /// Elongate an SDF along a single axis by `elongation`.
43    pub fn new(sdf: S, axis: Axis, elongation: T) -> Self {
44        Elongate {
45            sdf,
46            axis,
47            elongation,
48            _pd: std::marker::PhantomData,
49        }
50    }
51}
52
53impl<T, V, S> SDF<T, V> for Elongate<T, S, Dim3D>
54where
55    T: Copy + Add<T, Output = T> + Sub<T, Output = T> + Zero,
56    V: Vec3<T>,
57    S: SDF<T, V>,
58{
59    #[inline]
60    fn dist(&self, p: V) -> T {
61        let h = match self.axis {
62            Axis::X => V::new(self.elongation, T::zero(), T::zero()),
63            Axis::Y => V::new(T::zero(), self.elongation, T::zero()),
64            Axis::Z => V::new(T::zero(), T::zero(), self.elongation),
65        };
66        let q = p - p.clamp(-h, h);
67        self.sdf.dist(q)
68    }
69}
70
71impl<T, V, S> SDF<T, V> for Elongate<T, S, Dim2D>
72where
73    T: Copy + Add<T, Output = T> + Sub<T, Output = T> + Zero,
74    V: Vec2<T>,
75    S: SDF<T, V>,
76{
77    #[inline]
78    fn dist(&self, p: V) -> T {
79        let h = match self.axis {
80            Axis::X => V::new(self.elongation, T::zero()),
81            Axis::Y => V::new(T::zero(), self.elongation),
82            Axis::Z => panic!("Attempting to use Z axis to elongate 2d SDF"),
83        };
84        let q = p - p.clamp(-h, h);
85        self.sdf.dist(q)
86    }
87}
88
89/// Elongate an SDF along multiple axes.
90#[derive(Clone, Copy, Debug)]
91pub struct ElongateMulti<V, S, D> {
92    pub sdf: S,
93    pub elongation: V,
94    _pd: std::marker::PhantomData<D>,
95}
96
97impl<V, S, D> ElongateMulti<V, S, D> {
98    pub fn new(sdf: S, elongation: V) -> Self {
99        ElongateMulti {
100            sdf,
101            elongation,
102            _pd: std::marker::PhantomData,
103        }
104    }
105}
106
107impl<T, V, S> SDF<T, V> for ElongateMulti<V, S, Dim3D>
108where
109    T: Copy + Add<T, Output = T> + Sub<T, Output = T> + Zero + MaxMin,
110    V: Vec3<T>,
111    S: SDF<T, V>,
112{
113    #[inline]
114    fn dist(&self, p: V) -> T {
115        let q = p.abs() - self.elongation;
116        let t = q.y().max(q.z()).max(q.x()).min(T::zero());
117        self.sdf.dist(q.max(V::zero())) + t
118    }
119}
120
121impl<T, V, S> SDF<T, V> for ElongateMulti<V, S, Dim2D>
122where
123    T: Copy + Add<T, Output = T> + Sub<T, Output = T> + Zero + MaxMin,
124    V: Vec2<T>,
125    S: SDF<T, V>,
126{
127    #[inline]
128    fn dist(&self, p: V) -> T {
129        let q = p.abs() - self.elongation;
130        let t = q.x().max(q.y()).min(T::zero());
131        self.sdf.dist(q.max(V::zero())) + t
132    }
133}
134
135/// Translate an SDF.
136#[derive(Clone, Copy, Debug)]
137pub struct Translate<V, S> {
138    pub sdf: S,
139    pub translation: V,
140}
141
142impl<V, S> Translate<V, S> {
143    pub fn new(sdf: S, translation: V) -> Self {
144        Translate { sdf, translation }
145    }
146}
147
148impl<T, V, S> SDF<T, V> for Translate<V, S>
149where
150    T: Copy,
151    V: Vec<T>,
152    S: SDF<T, V>,
153{
154    #[inline]
155    fn dist(&self, p: V) -> T {
156        self.sdf.dist(p - self.translation)
157    }
158}
159
160/// Rotate an SDF.
161#[derive(Clone, Copy, Debug)]
162pub struct Rotate<R, S> {
163    pub sdf: S,
164    pub rotation: R,
165}
166
167impl<R, S> Rotate<R, S> {
168    pub fn new(sdf: S, rotation: R) -> Self {
169        Rotate { sdf, rotation }
170    }
171}
172
173impl<T, V, R, S> SDF<T, V> for Rotate<R, S>
174where
175    T: Copy,
176    V: Vec<T>,
177    S: SDF<T, V>,
178    R: Rotation<V> + Copy,
179{
180    #[inline]
181    fn dist(&self, p: V) -> T {
182        self.sdf.dist(self.rotation.rotate_vec(p))
183    }
184}
185
186/// Rotate an SDF.
187#[derive(Clone, Copy, Debug)]
188pub struct Scale<T, S> {
189    pub sdf: S,
190    pub scaling: T,
191}
192
193impl<T, S> Scale<T, S> {
194    pub fn new(sdf: S, scaling: T) -> Self {
195        Scale { sdf, scaling }
196    }
197}
198
199impl<T, V, S> SDF<T, V> for Scale<T, S>
200where
201    T: Copy + Mul<T, Output = T>,
202    V: Vec<T>,
203    S: SDF<T, V>,
204{
205    #[inline]
206    fn dist(&self, p: V) -> T {
207        self.sdf.dist(p / self.scaling) * self.scaling
208    }
209}