1use crate::prelude::*;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[derive(Debug, Clone, PartialEq)]
11pub enum ShapeBox {
12 Line(Line),
13 Rect(Rect),
14 Triangle(Triangle),
15 Circle(Circle),
16 Ellipse(Ellipse),
17 Polygon(Polygon),
18}
19
20macro_rules! per_shape_0 {
21 ($shape_box: expr, $method: path) => {
22 match $shape_box {
23 ShapeBox::Line(shape) => $method(shape),
24 ShapeBox::Rect(shape) => $method(shape),
25 ShapeBox::Circle(shape) => $method(shape),
26 ShapeBox::Triangle(shape) => $method(shape),
27 ShapeBox::Ellipse(shape) => $method(shape),
28 ShapeBox::Polygon(shape) => $method(shape),
29 }
30 };
31}
32
33macro_rules! per_shape_1 {
34 ($shape_box: expr, $method: path, $param1: expr) => {
35 match $shape_box {
36 ShapeBox::Line(shape) => $method(shape, $param1),
37 ShapeBox::Rect(shape) => $method(shape, $param1),
38 ShapeBox::Circle(shape) => $method(shape, $param1),
39 ShapeBox::Triangle(shape) => $method(shape, $param1),
40 ShapeBox::Ellipse(shape) => $method(shape, $param1),
41 ShapeBox::Polygon(shape) => $method(shape, $param1),
42 }
43 };
44}
45
46impl Shape for ShapeBox {
47 fn from_points(_: &[Coord]) -> Self
48 where
49 Self: Sized,
50 {
51 unimplemented!("ShapeBox can't be constructed from points")
52 }
53
54 fn rebuild(&self, points: &[Coord]) -> Self
55 where
56 Self: Sized,
57 {
58 match self {
59 ShapeBox::Line(_) => ShapeBox::Line(Line::from_points(points)),
60 ShapeBox::Rect(_) => ShapeBox::Rect(Rect::from_points(points)),
61 ShapeBox::Triangle(_) => ShapeBox::Triangle(Triangle::from_points(points)),
62 ShapeBox::Circle(_) => ShapeBox::Circle(Circle::from_points(points)),
63 ShapeBox::Ellipse(_) => ShapeBox::Ellipse(Ellipse::from_points(points)),
64 ShapeBox::Polygon(_) => ShapeBox::Polygon(Polygon::from_points(points)),
65 }
66 }
67
68 fn contains(&self, point: Coord) -> bool {
69 per_shape_1!(self, Shape::contains, point)
70 }
71
72 fn points(&self) -> Vec<Coord> {
73 per_shape_0!(self, Shape::points)
74 }
75
76 fn center(&self) -> Coord {
77 per_shape_0!(self, Shape::center)
78 }
79
80 fn outline_pixels(&self) -> Vec<Coord> {
81 per_shape_0!(self, Shape::outline_pixels)
82 }
83
84 fn filled_pixels(&self) -> Vec<Coord> {
85 per_shape_0!(self, Shape::filled_pixels)
86 }
87
88 fn to_shape_box(&self) -> ShapeBox {
90 self.clone()
91 }
92}
93
94impl IntersectsShape for ShapeBox {
95 fn intersects_rect(&self, rect: &Rect) -> bool {
96 per_shape_1!(self, IntersectsShape::intersects_rect, rect)
97 }
98
99 fn intersects_circle(&self, circle: &Circle) -> bool {
100 per_shape_1!(self, IntersectsShape::intersects_circle, circle)
101 }
102
103 fn intersects_line(&self, line: &Line) -> bool {
104 per_shape_1!(self, IntersectsShape::intersects_line, line)
105 }
106
107 fn intersects_triangle(&self, triangle: &Triangle) -> bool {
108 per_shape_1!(self, IntersectsShape::intersects_triangle, triangle)
109 }
110
111 fn intersects_ellipse(&self, ellipse: &Ellipse) -> bool {
112 per_shape_1!(self, IntersectsShape::intersects_ellipse, ellipse)
113 }
114
115 fn intersects_polygon(&self, polygon: &Polygon) -> bool {
116 per_shape_1!(self, IntersectsShape::intersects_polygon, polygon)
117 }
118}
119
120impl ContainsShape for ShapeBox {
121 fn contains_rect(&self, rect: &Rect) -> bool {
122 per_shape_1!(self, ContainsShape::contains_rect, rect)
123 }
124
125 fn contains_circle(&self, circle: &Circle) -> bool {
126 per_shape_1!(self, ContainsShape::contains_circle, circle)
127 }
128
129 fn contains_line(&self, line: &Line) -> bool {
130 per_shape_1!(self, ContainsShape::contains_line, line)
131 }
132
133 fn contains_triangle(&self, triangle: &Triangle) -> bool {
134 per_shape_1!(self, ContainsShape::contains_triangle, triangle)
135 }
136
137 fn contains_ellipse(&self, ellipse: &Ellipse) -> bool {
138 per_shape_1!(self, ContainsShape::contains_ellipse, ellipse)
139 }
140
141 fn contains_polygon(&self, polygon: &Polygon) -> bool {
142 per_shape_1!(self, ContainsShape::contains_polygon, polygon)
143 }
144}
145
146impl IntersectsContains for ShapeBox {}
147
148macro_rules! shapebox_shape {
149 ($shape: ty, $variant: path) => {
150 impl From<$shape> for ShapeBox {
151 fn from(value: $shape) -> Self {
152 $variant(value)
153 }
154 }
155 };
156}
157
158shapebox_shape!(Line, ShapeBox::Line);
159shapebox_shape!(Rect, ShapeBox::Rect);
160shapebox_shape!(Triangle, ShapeBox::Triangle);
161shapebox_shape!(Circle, ShapeBox::Circle);
162shapebox_shape!(Ellipse, ShapeBox::Ellipse);
163shapebox_shape!(Polygon, ShapeBox::Polygon);
164
165#[cfg(test)]
166mod test {
167 use crate::prelude::*;
168 use crate::shape_box::ShapeBox;
169
170 #[test]
171 fn basic() {
172 let rect_box = ShapeBox::from(Rect::new((10, 10), (30, 30)));
173 assert!(rect_box.contains(coord!(12, 15)));
174 assert!(rect_box.intersects_line(&Line::new((18, 0), (0, 30))));
175 }
176}