1use {
7 std::ops::Add,
8 euclid::{Point2D, Box2D, Vector2D as V2, Rotation2D, Angle},
9 num_traits::Float,
10 crate::sdf::{SDF, Union, Subtraction, Intersection, SmoothMin}
11};
12
13pub mod shapes;
14pub use shapes::*;
15
16#[derive(Debug, Copy, Clone)]
18pub struct PixelSpace;
19#[derive(Debug, Copy, Clone)]
21pub struct WorldSpace;
22
23pub type P2<P> = Point2D<P, WorldSpace>;
24
25pub trait BoundingBox<T> {
26 fn bounding_box(&self) -> Box2D<T, WorldSpace>;
27}
28
29pub trait Shape<T>: SDF<T> + BoundingBox<T> {
31 fn translate(self, offset: V2<T, WorldSpace>) -> Translation<Self, T> where Self: Sized {
32 Translation { shape: self, offset }
33 }
34 fn rotate(self, angle: Angle<T>) -> Rotation<Self, T> where Self: Sized {
36 Rotation { shape: self, angle }
37 }
38 fn scale(self, scale: T) -> Scale<Self, T> where Self: Sized {
40 Scale { shape: self, scale }
41 }
42 fn union<U>(self, other: U) -> Union<Self, U> where Self: Sized {
44 Union { s1: self, s2: other }
45 }
46 fn subtraction<U>(self, other: U) -> Subtraction<Self, U> where Self: Sized {
49 Subtraction { s1: self, s2: other }
50 }
51 fn intersection<U>(self, other: U) -> Intersection<Self, U> where Self: Sized {
53 Intersection { s1: self, s2: other }
54 }
55 fn smooth_min<U>(self, other: U, k: T) -> SmoothMin<T, Self, U> where Self: Sized {
59 SmoothMin { s1: self, s2: other, k }
60 }
61 #[cfg(feature = "drawing")]
62 #[cfg_attr(doc, doc(cfg(feature = "drawing")))]
63 fn texture<Tex>(self, texture: Tex) -> crate::drawing::Texture<Self, Tex> where Self: Sized {
64 crate::drawing::Texture { shape: self, texture }
65 }
66}
67impl <T, Sh> Shape<T> for Sh where Sh: SDF<T> + BoundingBox<T> {}
68
69#[derive(Debug, Copy, Clone)]
70pub struct Translation<S, T> {
71 pub shape: S,
72 pub offset: V2<T, WorldSpace>
73}
74impl <S, P> BoundingBox<P> for Translation<S, P>
75 where S: BoundingBox<P>,
76 P: Copy + Add<Output = P> {
77 fn bounding_box(&self) -> Box2D<P, WorldSpace> {
78 self.shape.bounding_box().translate(self.offset)
79 }
80}
81
82#[derive(Debug, Copy, Clone)]
84pub struct Rotation<S, T> {
85 pub shape: S,
86 pub angle: Angle<T>
87}
88impl <T, S> BoundingBox<T> for Rotation<S, T>
89 where S: BoundingBox<T>,
90 T: Float
91{
92 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
93 let bounding = self.shape.bounding_box();
94 let pivot = bounding.center();
95 let rot = |point: Point2D<_, _>| Rotation2D::new(self.angle)
96 .transform_point( (point - pivot).to_point())
97 + pivot.to_vector();
98 update_bounding_box(bounding, rot)
99 }
100}
101
102#[derive(Debug, Copy, Clone)]
104pub struct Scale<S, T> {
105 pub shape: S,
106 pub scale: T
107}
108impl <T, S> BoundingBox<T> for Scale<S, T>
109 where S: BoundingBox<T>,
110 T: Float
111{
112 fn bounding_box(&self) -> Box2D<T, WorldSpace> {
113 let c = self.shape.bounding_box().center().to_vector();
114 self.shape.bounding_box()
115 .translate(-c)
116 .scale(self.scale, self.scale)
117 .translate(c)
118 }
119}
120
121fn update_bounding_box<T>(
122 bounding: Box2D<T, WorldSpace>,
123 morphism: impl Fn(Point2D<T, WorldSpace>) -> Point2D<T, WorldSpace>
124) -> Box2D<T, WorldSpace>
125 where T: Float
126{
127 let pts = [
128 [bounding.min.x, bounding.min.y],
129 [bounding.max.x, bounding.min.y],
130 [bounding.max.x, bounding.max.y],
131 [bounding.min.x, bounding.max.y],
132 ];
133 let pts = pts.iter().cloned()
134 .map(|p| morphism(p.into()));
135 Box2D::from_points(pts)
136}
137
138#[derive(Copy, Clone, Debug)]
139pub struct DistPoint<D, P, Space> {
140 pub distance: D,
141 pub point: Point2D<P, Space>
142}
143
144impl<F: Float, P: Default, S> Default for DistPoint<F, P, S> {
145 fn default() -> Self {
146 Self {
147 distance: F::max_value() / (F::one() + F::one()),
148 point: Point2D::default()
149 }
150 }
151}
152
153impl<D: PartialEq, P, S> PartialEq for DistPoint<D, P, S> {
154 fn eq(&self, other: &Self) -> bool {
155 self.distance.eq(&other.distance)
156 }
157}
158
159impl<D: PartialOrd, P, S> PartialOrd for DistPoint<D, P, S> {
160 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
161 self.distance.partial_cmp(&other.distance)
162 }
163}
164
165impl<D: PartialEq, P, S> Eq for DistPoint<D, P, S> {}
166
167impl<P, S> std::cmp::Ord for DistPoint<f32, P, S> {
168 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
169 fn total_cmp(left: f32, right: f32) -> std::cmp::Ordering {
171 let mut left = left.to_bits() as i32;
172 let mut right = right.to_bits() as i32;
173 left ^= (((left >> 31) as u32) >> 1) as i32;
174 right ^= (((right >> 31) as u32) >> 1) as i32;
175
176 left.cmp(&right)
177 }
178 total_cmp(self.distance, other.distance)
179 }
180}