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