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