1 use super::{Drawable, PointCollection};
2 use crate::style::{Color, ShapeStyle, SizeDesc};
3 use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
4 
5 /**
6 An element representing a single pixel.
7 
8 See [`crate::element::EmptyElement`] for more information and examples.
9 */
10 pub struct Pixel<Coord> {
11     pos: Coord,
12     style: ShapeStyle,
13 }
14 
15 impl<Coord> Pixel<Coord> {
16     /**
17     Creates a new pixel.
18 
19     See [`crate::element::EmptyElement`] for more information and examples.
20     */
new<P: Into<Coord>, S: Into<ShapeStyle>>(pos: P, style: S) -> Self21     pub fn new<P: Into<Coord>, S: Into<ShapeStyle>>(pos: P, style: S) -> Self {
22         Self {
23             pos: pos.into(),
24             style: style.into(),
25         }
26     }
27 }
28 
29 impl<'a, Coord> PointCollection<'a, Coord> for &'a Pixel<Coord> {
30     type Point = &'a Coord;
31     type IntoIter = std::iter::Once<&'a Coord>;
point_iter(self) -> Self::IntoIter32     fn point_iter(self) -> Self::IntoIter {
33         std::iter::once(&self.pos)
34     }
35 }
36 
37 impl<Coord, DB: DrawingBackend> Drawable<DB> for Pixel<Coord> {
draw<I: Iterator<Item = BackendCoord>>( &self, mut points: I, backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>38     fn draw<I: Iterator<Item = BackendCoord>>(
39         &self,
40         mut points: I,
41         backend: &mut DB,
42         _: (u32, u32),
43     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
44         if let Some((x, y)) = points.next() {
45             return backend.draw_pixel((x, y), self.style.color.to_backend_color());
46         }
47         Ok(())
48     }
49 }
50 
51 #[cfg(test)]
52 #[test]
test_pixel_element()53 fn test_pixel_element() {
54     use crate::prelude::*;
55     let da = crate::create_mocked_drawing_area(300, 300, |m| {
56         m.check_draw_pixel(|c, (x, y)| {
57             assert_eq!(x, 150);
58             assert_eq!(y, 152);
59             assert_eq!(c, RED.to_rgba());
60         });
61 
62         m.drop_check(|b| {
63             assert_eq!(b.num_draw_pixel_call, 1);
64             assert_eq!(b.draw_count, 1);
65         });
66     });
67     da.draw(&Pixel::new((150, 152), &RED))
68         .expect("Drawing Failure");
69 }
70 
71 /// This is a deprecated type. Please use new name [`PathElement`] instead.
72 #[deprecated(note = "Use new name PathElement instead")]
73 pub type Path<Coord> = PathElement<Coord>;
74 
75 /// An element of a series of connected lines
76 pub struct PathElement<Coord> {
77     points: Vec<Coord>,
78     style: ShapeStyle,
79 }
80 impl<Coord> PathElement<Coord> {
81     /// Create a new path
82     /// - `points`: The iterator of the points
83     /// - `style`: The shape style
84     /// - returns the created element
new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self85     pub fn new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self {
86         Self {
87             points: points.into(),
88             style: style.into(),
89         }
90     }
91 }
92 
93 impl<'a, Coord> PointCollection<'a, Coord> for &'a PathElement<Coord> {
94     type Point = &'a Coord;
95     type IntoIter = &'a [Coord];
point_iter(self) -> &'a [Coord]96     fn point_iter(self) -> &'a [Coord] {
97         &self.points
98     }
99 }
100 
101 impl<Coord, DB: DrawingBackend> Drawable<DB> for PathElement<Coord> {
draw<I: Iterator<Item = BackendCoord>>( &self, points: I, backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>102     fn draw<I: Iterator<Item = BackendCoord>>(
103         &self,
104         points: I,
105         backend: &mut DB,
106         _: (u32, u32),
107     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
108         backend.draw_path(points, &self.style)
109     }
110 }
111 
112 #[cfg(test)]
113 #[test]
test_path_element()114 fn test_path_element() {
115     use crate::prelude::*;
116     let da = crate::create_mocked_drawing_area(300, 300, |m| {
117         m.check_draw_path(|c, s, path| {
118             assert_eq!(c, BLUE.to_rgba());
119             assert_eq!(s, 5);
120             assert_eq!(path, vec![(100, 101), (105, 107), (150, 157)]);
121         });
122         m.drop_check(|b| {
123             assert_eq!(b.num_draw_path_call, 1);
124             assert_eq!(b.draw_count, 1);
125         });
126     });
127     da.draw(&PathElement::new(
128         vec![(100, 101), (105, 107), (150, 157)],
129         Into::<ShapeStyle>::into(&BLUE).stroke_width(5),
130     ))
131     .expect("Drawing Failure");
132 }
133 
134 /// A rectangle element
135 pub struct Rectangle<Coord> {
136     points: [Coord; 2],
137     style: ShapeStyle,
138     margin: (u32, u32, u32, u32),
139 }
140 
141 impl<Coord> Rectangle<Coord> {
142     /// Create a new path
143     /// - `points`: The left upper and right lower corner of the rectangle
144     /// - `style`: The shape style
145     /// - returns the created element
new<S: Into<ShapeStyle>>(points: [Coord; 2], style: S) -> Self146     pub fn new<S: Into<ShapeStyle>>(points: [Coord; 2], style: S) -> Self {
147         Self {
148             points,
149             style: style.into(),
150             margin: (0, 0, 0, 0),
151         }
152     }
153 
154     /// Set the margin of the rectangle
155     /// - `t`: The top margin
156     /// - `b`: The bottom margin
157     /// - `l`: The left margin
158     /// - `r`: The right margin
set_margin(&mut self, t: u32, b: u32, l: u32, r: u32) -> &mut Self159     pub fn set_margin(&mut self, t: u32, b: u32, l: u32, r: u32) -> &mut Self {
160         self.margin = (t, b, l, r);
161         self
162     }
163 }
164 
165 impl<'a, Coord> PointCollection<'a, Coord> for &'a Rectangle<Coord> {
166     type Point = &'a Coord;
167     type IntoIter = &'a [Coord];
point_iter(self) -> &'a [Coord]168     fn point_iter(self) -> &'a [Coord] {
169         &self.points
170     }
171 }
172 
173 impl<Coord, DB: DrawingBackend> Drawable<DB> for Rectangle<Coord> {
draw<I: Iterator<Item = BackendCoord>>( &self, mut points: I, backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>174     fn draw<I: Iterator<Item = BackendCoord>>(
175         &self,
176         mut points: I,
177         backend: &mut DB,
178         _: (u32, u32),
179     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
180         match (points.next(), points.next()) {
181             (Some(a), Some(b)) => {
182                 let (mut a, mut b) = ((a.0.min(b.0), a.1.min(b.1)), (a.0.max(b.0), a.1.max(b.1)));
183                 a.1 += self.margin.0 as i32;
184                 b.1 -= self.margin.1 as i32;
185                 a.0 += self.margin.2 as i32;
186                 b.0 -= self.margin.3 as i32;
187                 backend.draw_rect(a, b, &self.style, self.style.filled)
188             }
189             _ => Ok(()),
190         }
191     }
192 }
193 
194 #[cfg(test)]
195 #[test]
test_rect_element()196 fn test_rect_element() {
197     use crate::prelude::*;
198     {
199         let da = crate::create_mocked_drawing_area(300, 300, |m| {
200             m.check_draw_rect(|c, s, f, u, d| {
201                 assert_eq!(c, BLUE.to_rgba());
202                 assert_eq!(f, false);
203                 assert_eq!(s, 5);
204                 assert_eq!([u, d], [(100, 101), (105, 107)]);
205             });
206             m.drop_check(|b| {
207                 assert_eq!(b.num_draw_rect_call, 1);
208                 assert_eq!(b.draw_count, 1);
209             });
210         });
211         da.draw(&Rectangle::new(
212             [(100, 101), (105, 107)],
213             Color::stroke_width(&BLUE, 5),
214         ))
215         .expect("Drawing Failure");
216     }
217 
218     {
219         let da = crate::create_mocked_drawing_area(300, 300, |m| {
220             m.check_draw_rect(|c, _, f, u, d| {
221                 assert_eq!(c, BLUE.to_rgba());
222                 assert_eq!(f, true);
223                 assert_eq!([u, d], [(100, 101), (105, 107)]);
224             });
225             m.drop_check(|b| {
226                 assert_eq!(b.num_draw_rect_call, 1);
227                 assert_eq!(b.draw_count, 1);
228             });
229         });
230         da.draw(&Rectangle::new([(100, 101), (105, 107)], BLUE.filled()))
231             .expect("Drawing Failure");
232     }
233 }
234 
235 /// A circle element
236 pub struct Circle<Coord, Size: SizeDesc> {
237     center: Coord,
238     size: Size,
239     style: ShapeStyle,
240 }
241 
242 impl<Coord, Size: SizeDesc> Circle<Coord, Size> {
243     /// Create a new circle element
244     /// - `coord` The center of the circle
245     /// - `size` The radius of the circle
246     /// - `style` The style of the circle
247     /// - Return: The newly created circle element
new<S: Into<ShapeStyle>>(coord: Coord, size: Size, style: S) -> Self248     pub fn new<S: Into<ShapeStyle>>(coord: Coord, size: Size, style: S) -> Self {
249         Self {
250             center: coord,
251             size,
252             style: style.into(),
253         }
254     }
255 }
256 
257 impl<'a, Coord, Size: SizeDesc> PointCollection<'a, Coord> for &'a Circle<Coord, Size> {
258     type Point = &'a Coord;
259     type IntoIter = std::iter::Once<&'a Coord>;
point_iter(self) -> std::iter::Once<&'a Coord>260     fn point_iter(self) -> std::iter::Once<&'a Coord> {
261         std::iter::once(&self.center)
262     }
263 }
264 
265 impl<Coord, DB: DrawingBackend, Size: SizeDesc> Drawable<DB> for Circle<Coord, Size> {
draw<I: Iterator<Item = BackendCoord>>( &self, mut points: I, backend: &mut DB, ps: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>266     fn draw<I: Iterator<Item = BackendCoord>>(
267         &self,
268         mut points: I,
269         backend: &mut DB,
270         ps: (u32, u32),
271     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
272         if let Some((x, y)) = points.next() {
273             let size = self.size.in_pixels(&ps).max(0) as u32;
274             return backend.draw_circle((x, y), size, &self.style, self.style.filled);
275         }
276         Ok(())
277     }
278 }
279 
280 #[cfg(test)]
281 #[test]
test_circle_element()282 fn test_circle_element() {
283     use crate::prelude::*;
284     let da = crate::create_mocked_drawing_area(300, 300, |m| {
285         m.check_draw_circle(|c, _, f, s, r| {
286             assert_eq!(c, BLUE.to_rgba());
287             assert_eq!(f, false);
288             assert_eq!(s, (150, 151));
289             assert_eq!(r, 20);
290         });
291         m.drop_check(|b| {
292             assert_eq!(b.num_draw_circle_call, 1);
293             assert_eq!(b.draw_count, 1);
294         });
295     });
296     da.draw(&Circle::new((150, 151), 20, &BLUE))
297         .expect("Drawing Failure");
298 }
299 
300 /// An element of a filled polygon
301 pub struct Polygon<Coord> {
302     points: Vec<Coord>,
303     style: ShapeStyle,
304 }
305 impl<Coord> Polygon<Coord> {
306     /// Create a new polygon
307     /// - `points`: The iterator of the points
308     /// - `style`: The shape style
309     /// - returns the created element
new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self310     pub fn new<P: Into<Vec<Coord>>, S: Into<ShapeStyle>>(points: P, style: S) -> Self {
311         Self {
312             points: points.into(),
313             style: style.into(),
314         }
315     }
316 }
317 
318 impl<'a, Coord> PointCollection<'a, Coord> for &'a Polygon<Coord> {
319     type Point = &'a Coord;
320     type IntoIter = &'a [Coord];
point_iter(self) -> &'a [Coord]321     fn point_iter(self) -> &'a [Coord] {
322         &self.points
323     }
324 }
325 
326 impl<Coord, DB: DrawingBackend> Drawable<DB> for Polygon<Coord> {
draw<I: Iterator<Item = BackendCoord>>( &self, points: I, backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>327     fn draw<I: Iterator<Item = BackendCoord>>(
328         &self,
329         points: I,
330         backend: &mut DB,
331         _: (u32, u32),
332     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
333         backend.fill_polygon(points, &self.style.color.to_backend_color())
334     }
335 }
336 
337 #[cfg(test)]
338 #[test]
test_polygon_element()339 fn test_polygon_element() {
340     use crate::prelude::*;
341     let points = vec![(100, 100), (50, 500), (300, 400), (200, 300), (550, 200)];
342     let expected_points = points.clone();
343 
344     let da = crate::create_mocked_drawing_area(800, 800, |m| {
345         m.check_fill_polygon(move |c, p| {
346             assert_eq!(c, BLUE.to_rgba());
347             assert_eq!(expected_points.len(), p.len());
348             assert_eq!(expected_points, p);
349         });
350         m.drop_check(|b| {
351             assert_eq!(b.num_fill_polygon_call, 1);
352             assert_eq!(b.draw_count, 1);
353         });
354     });
355 
356     da.draw(&Polygon::new(points.clone(), &BLUE))
357         .expect("Drawing Failure");
358 }
359