four_bar/plot/
dashed_line.rs1use super::{to_f, to_i};
2use plotters::{
3 element::{Drawable, PointCollection},
4 style::{ShapeStyle, SizeDesc},
5};
6use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
7
8pub(crate) struct DashedPath<I: Iterator + Clone, Size: SizeDesc> {
9 points: I,
10 size: Size,
11 spacing: Size,
12 style: ShapeStyle,
13}
14
15impl<I: Iterator + Clone, Size: SizeDesc> DashedPath<I, Size> {
16 pub(crate) fn new<I0, S>(points: I0, size: Size, spacing: Size, style: S) -> Self
17 where
18 I0: IntoIterator<IntoIter = I>,
19 S: Into<ShapeStyle>,
20 {
21 Self {
22 points: points.into_iter(),
23 size,
24 spacing,
25 style: style.into(),
26 }
27 }
28
29 pub(crate) fn series(self) -> std::iter::Once<Self> {
30 std::iter::once(self)
31 }
32}
33
34impl<'a, I: Iterator + Clone, Size: SizeDesc> PointCollection<'a, I::Item>
35 for &'a DashedPath<I, Size>
36{
37 type Point = I::Item;
38 type IntoIter = I;
39
40 fn point_iter(self) -> Self::IntoIter {
41 self.points.clone()
42 }
43}
44
45impl<I0: Iterator + Clone, Size: SizeDesc, DB: DrawingBackend> Drawable<DB>
46 for DashedPath<I0, Size>
47{
48 fn draw<I: Iterator<Item = BackendCoord>>(
49 &self,
50 mut points: I,
51 backend: &mut DB,
52 ps: (u32, u32),
53 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
54 let mut start = match points.next() {
55 Some(c) => to_f(c),
56 None => return Ok(()),
57 };
58 let size = self.size.in_pixels(&ps).max(0) as f32;
59 if size == 0. {
60 return Ok(());
61 }
62 let spacing = self.spacing.in_pixels(&ps).max(0) as f32;
63 let mut dist = 0.;
64 let mut is_solid = true;
65 let mut queue = vec![to_i(start)];
66 for curr in points {
67 let end = to_f(curr);
68 while start != end {
70 let (dx, dy) = (end.0 - start.0, end.1 - start.1);
71 let d = dx.hypot(dy);
72 let size = if is_solid { size } else { spacing };
73 let left = size - dist;
74 if left < d {
76 let t = left / d;
77 start = (start.0 + dx * t, start.1 + dy * t);
78 dist += left;
79 } else {
80 start = end;
81 dist += d;
82 }
83 if is_solid {
85 queue.push(to_i(start));
86 }
87 if size <= dist {
88 if is_solid {
89 backend.draw_path(queue.drain(..), &self.style)?;
90 } else {
91 queue.push(to_i(start));
92 }
93 dist = 0.;
94 is_solid = !is_solid;
95 }
96 }
97 }
98 if queue.len() > 1 {
99 backend.draw_path(queue, &self.style)?;
100 }
101 Ok(())
102 }
103}