1use crate::{
2 Angle, Circle, Float, Line, Polygon, Polygonal, Projection, Quad, Radians, Ray, RayHit, Rect,
3 Shape, Triangle, Vec2,
4};
5
6pub type DynShapeF = DynShape<f32>;
7
8#[derive(Debug, Clone)]
17pub enum DynShape<T> {
18 Circle(Circle<T>),
19 Triangle(Triangle<T>),
20 Rect(Rect<T>),
21 Quad(Quad<T>),
22 Polygon(Polygon<T>),
23}
24
25impl<T: Float> DynShape<T> {
26 #[inline]
28 pub fn overlaps(&self, other: &Self) -> bool {
29 match other {
30 Self::Circle(sh) => self.overlaps_circ(sh),
31 Self::Triangle(sh) => self.overlaps_poly(sh),
32 Self::Rect(sh) => self.overlaps_rect(sh),
33 Self::Quad(sh) => self.overlaps_poly(sh),
34 Self::Polygon(sh) => self.overlaps_poly(sh),
35 }
36 }
37
38 #[inline]
41 pub fn extract_from(&self, other: &Self) -> Option<Vec2<T>> {
42 match other {
43 Self::Circle(sh) => self.extract_from_circ(sh),
44 Self::Triangle(sh) => self.extract_from_poly(sh),
45 Self::Rect(sh) => self.extract_from_poly(sh),
46 Self::Quad(sh) => self.extract_from_poly(sh),
47 Self::Polygon(sh) => self.extract_from_poly(sh),
48 }
49 }
50
51 pub fn hull_points(&self, circle_seg_len: T, plot: impl FnMut(Vec2<T>)) {
55 match self {
56 Self::Circle(sh) => sh.hull_points(circle_seg_len, Radians(T::ZERO), plot),
57 Self::Triangle(sh) => sh.0.iter().copied().for_each(plot),
58 Self::Rect(sh) => sh.corners().into_iter().for_each(plot),
59 Self::Quad(sh) => sh.0.iter().copied().for_each(plot),
60 Self::Polygon(sh) => sh.points().iter().copied().for_each(plot),
61 }
62 }
63
64 pub fn hull_points_n(&self, circle_count: T, plot: impl FnMut(Vec2<T>)) {
66 match self {
67 Self::Circle(sh) => sh.hull_points_n(circle_count, Radians(T::ZERO), plot),
68 Self::Triangle(sh) => sh.0.iter().copied().for_each(plot),
69 Self::Rect(sh) => sh.corners().into_iter().for_each(plot),
70 Self::Quad(sh) => sh.0.iter().copied().for_each(plot),
71 Self::Polygon(sh) => sh.points().iter().copied().for_each(plot),
72 }
73 }
74
75 pub fn hull_edges(&self, circle_seg_len: T, plot: impl FnMut(Line<T>)) {
79 match self {
80 Self::Circle(sh) => sh.hull_edges(circle_seg_len, Radians(T::ZERO), plot),
81 Self::Triangle(sh) => sh.visit_edges(plot),
82 Self::Rect(sh) => sh.visit_edges(plot),
83 Self::Quad(sh) => sh.visit_edges(plot),
84 Self::Polygon(sh) => sh.visit_edges(plot),
85 }
86 }
87
88 pub fn hull_edges_n(&self, circle_count: T, plot: impl FnMut(Line<T>)) {
92 match self {
93 Self::Circle(sh) => sh.hull_edges_n(circle_count, Radians(T::ZERO), plot),
94 Self::Triangle(sh) => sh.visit_edges(plot),
95 Self::Rect(sh) => sh.visit_edges(plot),
96 Self::Quad(sh) => sh.visit_edges(plot),
97 Self::Polygon(sh) => sh.visit_edges(plot),
98 }
99 }
100
101 pub fn transform_into(
102 &self,
103 into: &mut Self,
104 circle_out: CircleOut<T>,
105 rect_out: RectOut,
106 f: impl FnMut(Vec2<T>) -> Vec2<T>,
107 ) {
108 match self {
109 Self::Circle(sh) => match circle_out {
110 CircleOut::Circle => {
111 *into = Self::Circle(sh.transform_by_retain(f));
112 }
113 CircleOut::SegCount { count, angle } => {
114 if let Self::Polygon(into) = into {
115 sh.transform_by_into_n(count, angle, into, f);
116 } else {
117 *into = Self::Polygon(sh.transform_by_n(count, angle, f));
118 }
119 }
120 CircleOut::SegLen { len, angle } => {
121 if let Self::Polygon(into) = into {
122 sh.transform_by_into(len, angle, into, f);
123 } else {
124 *into = Self::Polygon(sh.transform_by(len, angle, f));
125 }
126 }
127 },
128 Self::Triangle(sh) => {
129 if let Self::Triangle(into) = into {
130 *into = sh.transform_by(f);
131 } else {
132 *into = Self::Triangle(sh.transform_by(f));
133 }
134 }
135 Self::Rect(sh) => match rect_out {
136 RectOut::Rect => {
137 if let Self::Rect(into) = into {
138 *into = sh.transform_by_retain(f);
139 } else {
140 *into = Self::Rect(sh.transform_by_retain(f));
141 }
142 }
143 RectOut::Quad => {
144 if let Self::Quad(into) = into {
145 *into = sh.transform_by(f);
146 } else {
147 *into = Self::Quad(sh.transform_by(f));
148 }
149 }
150 },
151 Self::Quad(sh) => {
152 if let Self::Quad(into) = into {
153 *into = sh.transform_by(f);
154 } else {
155 *into = Self::Quad(sh.transform_by(f));
156 }
157 }
158 Self::Polygon(sh) => {
159 if let Self::Polygon(into) = into {
160 sh.transform_by_into(into, f);
161 } else {
162 *into = Self::Polygon(sh.transform_by(f));
163 }
164 }
165 }
166 }
167}
168
169macro_rules! delegate {
170 ($this:ident, $call:ident, $($arg:ident),*) => {
171 match $this {
172 Self::Circle(sh) => sh.$call($($arg),*),
173 Self::Triangle(sh) => sh.$call($($arg),*),
174 Self::Rect(sh) => sh.$call($($arg),*),
175 Self::Quad(sh) => sh.$call($($arg),*),
176 Self::Polygon(sh) => sh.$call($($arg),*),
177 }
178 }
179}
180
181impl<T: Float> Shape<T> for DynShape<T> {
182 #[inline]
183 fn centroid(&self) -> Vec2<T> {
184 delegate!(self, centroid,)
185 }
186
187 #[inline]
188 fn contains(&self, p: Vec2<T>) -> bool {
189 delegate!(self, contains, p)
190 }
191
192 #[inline]
193 fn bounds(&self) -> Rect<T> {
194 delegate!(self, bounds,)
195 }
196
197 #[inline]
198 fn project_onto_axis(&self, axis: Vec2<T>) -> Projection<T> {
199 delegate!(self, project_onto_axis, axis)
200 }
201
202 #[inline]
203 fn project_point(&self, p: Vec2<T>) -> Vec2<T> {
204 delegate!(self, project_point, p)
205 }
206
207 #[inline]
208 fn rayhit(&self, ray: &Ray<T>) -> bool {
209 delegate!(self, rayhit, ray)
210 }
211
212 #[inline]
213 fn raycast(&self, ray: &Ray<T>) -> Option<RayHit<T>> {
214 delegate!(self, raycast, ray)
215 }
216
217 #[inline]
218 fn overlaps_rect(&self, rect: &Rect<T>) -> bool {
219 delegate!(self, overlaps_rect, rect)
220 }
221
222 #[inline]
223 fn overlaps_circ(&self, circ: &Circle<T>) -> bool {
224 delegate!(self, overlaps_circ, circ)
225 }
226
227 #[inline]
228 fn overlaps_poly<P: Polygonal<T>>(&self, poly: &P) -> bool {
229 delegate!(self, overlaps_poly, poly)
230 }
231
232 #[inline]
233 fn extract_from_circ(&self, circ: &Circle<T>) -> Option<Vec2<T>> {
234 delegate!(self, extract_from_circ, circ)
235 }
236
237 #[inline]
238 fn extract_from_poly<P: Polygonal<T>>(&self, poly: &P) -> Option<Vec2<T>> {
239 delegate!(self, extract_from_poly, poly)
240 }
241
242 #[inline]
243 fn is_convex(&self) -> bool {
244 delegate!(self, is_convex,)
245 }
246}
247
248impl<T> From<Circle<T>> for DynShape<T> {
249 #[inline]
250 fn from(value: Circle<T>) -> Self {
251 Self::Circle(value)
252 }
253}
254
255impl<T> From<Triangle<T>> for DynShape<T> {
256 #[inline]
257 fn from(value: Triangle<T>) -> Self {
258 Self::Triangle(value)
259 }
260}
261
262impl<T> From<Rect<T>> for DynShape<T> {
263 #[inline]
264 fn from(value: Rect<T>) -> Self {
265 Self::Rect(value)
266 }
267}
268
269impl<T> From<Quad<T>> for DynShape<T> {
270 #[inline]
271 fn from(value: Quad<T>) -> Self {
272 Self::Quad(value)
273 }
274}
275
276impl<T> From<Polygon<T>> for DynShape<T> {
277 #[inline]
278 fn from(value: Polygon<T>) -> Self {
279 Self::Polygon(value)
280 }
281}
282
283#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
284pub enum CircleOut<T> {
285 Circle,
286 SegCount { count: T, angle: Radians<T> },
287 SegLen { len: T, angle: Radians<T> },
288}
289
290impl<T> CircleOut<T> {
291 #[inline]
292 pub fn seg_count(count: T, angle: impl Angle<T>) -> Self {
293 Self::SegCount {
294 count,
295 angle: angle.to_radians(),
296 }
297 }
298
299 #[inline]
300 pub fn seg_len(len: T, angle: impl Angle<T>) -> Self {
301 Self::SegLen {
302 len,
303 angle: angle.to_radians(),
304 }
305 }
306}
307
308#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
309pub enum RectOut {
310 Rect,
311 Quad,
312}