1use {
2 euclid::{Point2D, Vector2D as V2, Rotation2D, Box2D},
3 crate::{
4 geometry::{self, WorldSpace, Shape, Rotation, Scale, Translation, BoundingBox},
5 },
6 num_traits::{Float, Signed},
7 std::ops::{Neg, Sub}
8};
9
10pub trait SDF<T> {
12 fn sdf(&self, p: Point2D<T, WorldSpace>) -> T;
13}
14
15impl <S, P: Float> SDF<P> for Translation<S, P>
16 where S: Shape<P>,
17 P: Clone + Sub<Output = P> {
18 fn sdf(&self, pixel: Point2D<P, WorldSpace>) -> P {
19 self.shape.sdf(pixel - self.offset)
20 }
21}
22
23impl <S, P> SDF<P> for Rotation<S, P>
24 where S: Shape<P>,
25 P: Float {
26 fn sdf(&self, pixel: Point2D<P, WorldSpace>) -> P {
27 let pivot = self.shape.bounding_box().center();
28 let pixel = Rotation2D::new(self.angle)
29 .transform_point( (pixel - pivot).to_point())
30 + pivot.to_vector();
31
32 self.shape.sdf(pixel)
33 }
34}
35
36impl <S, P> SDF<P> for Scale<S, P>
37 where S: Shape<P>,
38 P: Float {
39 fn sdf(&self, pixel: Point2D<P, WorldSpace>) -> P {
40 let c = self.shape.bounding_box().center();
41 let pixel = ((pixel - c) / self.scale + c.to_vector())
42 .to_point();
43 self.shape.sdf(pixel) * self.scale
44 }
45}
46
47pub fn boundary_rect<T: Float + Signed>(pixel: Point2D<T, WorldSpace>) -> T {
49 let p5 = T::one() / (T::one() + T::one());
50 -geometry::Rect { size: Point2D::splat(T::one()) }
51 .translate(V2::splat(p5))
52 .sdf(pixel)
53}
54
55#[derive(Clone, Copy, Debug)]
57pub struct Union<S1, S2> {
58 pub s1: S1,
59 pub s2: S2,
60}
61
62impl<T, S1, S2> SDF<T> for Union<S1, S2>
63 where T: Float,
64 S1: SDF<T>,
65 S2: SDF<T> {
66 fn sdf(&self, pixel: Point2D<T, WorldSpace>) -> T {
67 self.s1.sdf(pixel).min(self.s2.sdf(pixel))
68 }}
69
70impl<T, S1, S2> BoundingBox<T> for Union<S1, S2>
71 where T: Copy + PartialOrd,
72 S1: BoundingBox<T>,
73 S2: BoundingBox<T> {
74 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
75 self.s1.bounding_box().union(&self.s2.bounding_box())
76 }}
77
78#[derive(Clone, Copy, Debug)]
81pub struct Subtraction<S1, S2> {
82 pub s1: S1,
83 pub s2: S2,
84}
85
86impl<T, S1, S2> SDF<T> for Subtraction<S1, S2>
87 where T: Float,
88 S1: SDF<T>,
89 S2: SDF<T> {
90 fn sdf(&self, pixel: Point2D<T, WorldSpace>) -> T {
91 (-self.s2.sdf(pixel)).max(self.s1.sdf(pixel))
92 }}
93
94impl<T, S1, S2> BoundingBox<T> for Subtraction<S1, S2>
95 where T: Copy + PartialOrd,
96 S1: BoundingBox<T>,
97 S2: BoundingBox<T> {
98 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
99 self.s1.bounding_box().union(&self.s2.bounding_box())
100 }}
101
102#[derive(Clone, Copy, Debug)]
104pub struct Intersection<S1, S2> {
105 pub s1: S1,
106 pub s2: S2,
107}
108
109impl<T, S1, S2> SDF<T> for Intersection<S1, S2>
110 where T: Float,
111 S1: SDF<T>,
112 S2: SDF<T> {
113 fn sdf(&self, pixel: Point2D<T, WorldSpace>) -> T {
114 self.s1.sdf(pixel).max(self.s2.sdf(pixel))
115 }}
116
117impl<T, S1, S2> BoundingBox<T> for Intersection<S1, S2>
118 where T: Copy + PartialOrd + num_traits::One + Neg<Output = T>,
119 S1: BoundingBox<T>,
120 S2: BoundingBox<T> {
121 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
122 self.s1.bounding_box()
123 .intersection(&self.s2.bounding_box())
124 .unwrap_or(Box2D {
125 min: Point2D::splat(-T::one()),
126 max: Point2D::splat(-T::one())
127 })
128 }}
129
130#[derive(Clone, Copy, Debug)]
134pub struct SmoothMin<T, S1, S2> {
135 pub s1: S1,
136 pub s2: S2,
137 pub k: T
138}
139
140impl<T, S1, S2> SDF<T> for SmoothMin<T, S1, S2>
141 where T: Float,
142 S1: SDF<T>,
143 S2: SDF<T> {
144 fn sdf(&self, pixel: Point2D<T, WorldSpace>) -> T {
145 let (s1, s2) = (self.s1.sdf(pixel), self.s2.sdf(pixel));
146 let res = (-self.k * s1).exp2() + (-self.k * s2).exp2();
147 -res.log2() / self.k
148 }}
149
150impl<T, S1, S2> BoundingBox<T> for SmoothMin<T, S1, S2>
151 where T: Copy + PartialOrd,
152 S1: BoundingBox<T>,
153 S2: BoundingBox<T> {
154 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
155 self.s1.bounding_box().union(&self.s2.bounding_box())
156 }}