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     */
make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self19     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     */
new<T: Into<ShapeStyle>>(coord: Coord, size: Size, style: T) -> Self39     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>;
point_iter(self) -> 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> {
draw<I: Iterator<Item = BackendCoord>>( &self, mut points: I, backend: &mut DB, ps: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>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     */
new<T: Into<ShapeStyle>>(coord: Coord, size: Size, style: T) -> Self91     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>;
point_iter(self) -> 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> {
draw<I: Iterator<Item = BackendCoord>>( &self, mut points: I, backend: &mut DB, ps: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>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> {
make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self133     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> {
make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self139     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> {
make_point(pos: Coord, size: Size, style: ShapeStyle) -> Self145     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> {
make_point(pos: Coord, _: Size, style: ShapeStyle) -> Self151     fn make_point(pos: Coord, _: Size, style: ShapeStyle) -> Self {
152         Self::new(pos, style)
153     }
154 }
155