1 | use super::*; |
2 | use super::{Drawable, PointCollection}; |
3 | use crate::style::{Color, ShapeStyle, SizeDesc}; |
4 | use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind}; |
5 | |
6 | /** |
7 | A common trait for elements that can be interpreted as points: A cross, a circle, a triangle marker... |
8 | |
9 | This is used internally by Plotters and should probably not be included in user code. |
10 | See [`EmptyElement`] for more information and examples. |
11 | */ |
12 | pub trait PointElement<Coord, Size: SizeDesc> { |
13 | /** |
14 | Point creator. |
15 | |
16 | This is used internally by Plotters and should probably not be included in user code. |
17 | See [`EmptyElement`] for more information and examples. |
18 | */ |
19 | fn make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self; |
20 | } |
21 | |
22 | /** |
23 | A cross marker for visualizing data series. |
24 | |
25 | See [`EmptyElement`] for more information and examples. |
26 | */ |
27 | pub struct Cross<Coord, Size: SizeDesc> { |
28 | center: Coord, |
29 | size: Size, |
30 | style: ShapeStyle, |
31 | } |
32 | |
33 | impl<Coord, Size: SizeDesc> Cross<Coord, Size> { |
34 | /** |
35 | Creates a cross marker. |
36 | |
37 | See [`EmptyElement`] for more information and examples. |
38 | */ |
39 | pub fn new<T: Into<ShapeStyle>>(coord: Coord, size: Size, style: T) -> Self { |
40 | Self { |
41 | center: coord, |
42 | size, |
43 | style: style.into(), |
44 | } |
45 | } |
46 | } |
47 | |
48 | impl<'a, Coord: 'a, Size: SizeDesc> PointCollection<'a, Coord> for &'a Cross<Coord, Size> { |
49 | type Point = &'a Coord; |
50 | type IntoIter = std::iter::Once<&'a Coord>; |
51 | fn point_iter(self) -> std::iter::Once<&'a Coord> { |
52 | std::iter::once(&self.center) |
53 | } |
54 | } |
55 | |
56 | impl<Coord, DB: DrawingBackend, Size: SizeDesc> Drawable<DB> for Cross<Coord, Size> { |
57 | fn draw<I: Iterator<Item = BackendCoord>>( |
58 | &self, |
59 | mut points: I, |
60 | backend: &mut DB, |
61 | ps: (u32, u32), |
62 | ) -> Result<(), DrawingErrorKind<DB::ErrorType>> { |
63 | if let Some((x, y)) = points.next() { |
64 | let size = self.size.in_pixels(&ps); |
65 | let (x0, y0) = (x - size, y - size); |
66 | let (x1, y1) = (x + size, y + size); |
67 | backend.draw_line((x0, y0), (x1, y1), &self.style)?; |
68 | backend.draw_line((x0, y1), (x1, y0), &self.style)?; |
69 | } |
70 | Ok(()) |
71 | } |
72 | } |
73 | |
74 | /** |
75 | A triangle marker for visualizing data series. |
76 | |
77 | See [`EmptyElement`] for more information and examples. |
78 | */ |
79 | pub struct TriangleMarker<Coord, Size: SizeDesc> { |
80 | center: Coord, |
81 | size: Size, |
82 | style: ShapeStyle, |
83 | } |
84 | |
85 | impl<Coord, Size: SizeDesc> TriangleMarker<Coord, Size> { |
86 | /** |
87 | Creates a triangle marker. |
88 | |
89 | See [`EmptyElement`] for more information and examples. |
90 | */ |
91 | pub fn new<T: Into<ShapeStyle>>(coord: Coord, size: Size, style: T) -> Self { |
92 | Self { |
93 | center: coord, |
94 | size, |
95 | style: style.into(), |
96 | } |
97 | } |
98 | } |
99 | |
100 | impl<'a, Coord: 'a, Size: SizeDesc> PointCollection<'a, Coord> for &'a TriangleMarker<Coord, Size> { |
101 | type Point = &'a Coord; |
102 | type IntoIter = std::iter::Once<&'a Coord>; |
103 | fn point_iter(self) -> std::iter::Once<&'a Coord> { |
104 | std::iter::once(&self.center) |
105 | } |
106 | } |
107 | |
108 | impl<Coord, DB: DrawingBackend, Size: SizeDesc> Drawable<DB> for TriangleMarker<Coord, Size> { |
109 | fn draw<I: Iterator<Item = BackendCoord>>( |
110 | &self, |
111 | mut points: I, |
112 | backend: &mut DB, |
113 | ps: (u32, u32), |
114 | ) -> Result<(), DrawingErrorKind<DB::ErrorType>> { |
115 | if let Some((x, y)) = points.next() { |
116 | let size = self.size.in_pixels(&ps); |
117 | let points = [-90, -210, -330] |
118 | .iter() |
119 | .map(|deg| f64::from(*deg) * std::f64::consts::PI / 180.0) |
120 | .map(|rad| { |
121 | ( |
122 | (rad.cos() * f64::from(size) + f64::from(x)).ceil() as i32, |
123 | (rad.sin() * f64::from(size) + f64::from(y)).ceil() as i32, |
124 | ) |
125 | }); |
126 | backend.fill_polygon(points, &self.style.color.to_backend_color())?; |
127 | } |
128 | Ok(()) |
129 | } |
130 | } |
131 | |
132 | impl<Coord, Size: SizeDesc> PointElement<Coord, Size> for Cross<Coord, Size> { |
133 | fn make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self { |
134 | Self::new(pos, size, style) |
135 | } |
136 | } |
137 | |
138 | impl<Coord, Size: SizeDesc> PointElement<Coord, Size> for TriangleMarker<Coord, Size> { |
139 | fn make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self { |
140 | Self::new(pos, size, style) |
141 | } |
142 | } |
143 | |
144 | impl<Coord, Size: SizeDesc> PointElement<Coord, Size> for Circle<Coord, Size> { |
145 | fn make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self { |
146 | Self::new(pos, size, style) |
147 | } |
148 | } |
149 | |
150 | impl<Coord, Size: SizeDesc> PointElement<Coord, Size> for Pixel<Coord> { |
151 | fn make_point(pos: Coord, _: Size, style: ShapeStyle) -> Self { |
152 | Self::new(pos, style) |
153 | } |
154 | } |
155 | |