1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use crate::curve::Curve;
use embedded_graphics::drawable::Drawable;
use embedded_graphics::DrawTarget;
use embedded_graphics::prelude::Point;
use embedded_graphics::pixelcolor::PixelColor;
use crate::axis::{Scale, Placement, Axis};
use embedded_graphics::style::TextStyleBuilder;
use embedded_graphics::fonts::Font6x8;

/// Display agnostic single curve plot object
pub struct SinglePlot<'a> {
    /// curve to be drawn on the plot
    curve: &'a Curve<'a>,
    /// range of X axis on which curve will be drawn
    x_scale: Scale,
    /// range of Y axis on which curve will be drawn
    y_scale: Scale,
}

impl<'a> SinglePlot<'a> {
    /// create SinglePlot object with manual range
    pub fn new(curve: &'a Curve<'a>, x_scale: Scale, y_scale: Scale) -> SinglePlot {
        SinglePlot { curve, x_scale, y_scale }
    }

    //TODO: add auto range plot constructor

    /// convert to drawable form for specific display
    pub fn into_drawable<C: PixelColor + Default>(self, top_left: Point, bottom_right: Point) -> DrawableSinglePlot<'a, C> {
        DrawableSinglePlot { plot: self, color: None, text_color: None, axis_color: None, thickness: None, axis_thickness: None, top_left, bottom_right }
    }
}

/// Drawable single plot object, constructed for specific display
pub struct DrawableSinglePlot<'a, C>
    where
        C: PixelColor + Default,
{
    plot: SinglePlot<'a>,
    color: Option<C>,
    text_color: Option<C>,
    axis_color: Option<C>,
    thickness: Option<usize>,
    axis_thickness: Option<usize>,
    top_left: Point,
    bottom_right: Point,
}

/// builder methods to modify plot decoration
impl<'a, C> DrawableSinglePlot<'a, C>
    where
        C: PixelColor + Default,
{
    pub fn set_color(mut self, color: C) -> DrawableSinglePlot<'a, C> {
        self.color = Some(color);
        self
    }

    /// if not set, main color will be used
    pub fn set_text_color(mut self, color: C) -> DrawableSinglePlot<'a, C> {
        self.text_color = Some(color);
        self
    }

    /// if not set, main color will be used
    pub fn set_axis_color(mut self, color: C) -> DrawableSinglePlot<'a, C> {
        self.axis_color = Some(color);
        self
    }

    /// set curve thickness
    pub fn set_thickness(mut self, thickness: usize) -> DrawableSinglePlot<'a, C> {
        self.thickness = Some(thickness);
        self
    }

    ///set axis thickness
    pub fn set_axis_thickness(mut self, thickness: usize) -> DrawableSinglePlot<'a, C> {
        self.axis_thickness = Some(thickness);
        self
    }

    //TODO: add axis ticks thickness

}

impl<'a, C> Drawable<C> for DrawableSinglePlot<'a, C>
    where
        C: PixelColor + Default,
{
    /// most important function - draw the plot on the display
    fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), D::Error> {
        let color = self.color.unwrap_or_default();
        let text_color = self.text_color.unwrap_or(color);
        let axis_color = self.axis_color.unwrap_or(color);
        let thickness = self.thickness.unwrap_or(2);
        let axis_thickness = self.axis_thickness.unwrap_or(thickness);

        let text_style = TextStyleBuilder::new(Font6x8)
            .text_color(text_color)
            .build();

        Axis::new( self.plot.curve.x_range.clone())
            .set_title("X")
            .set_scale(self.plot.x_scale)
            .into_drawable_axis(Placement::X { x1: self.top_left.x, x2: self.bottom_right.x, y: self.bottom_right.y })
            .set_color(axis_color)
            .set_text_style(text_style)
            .set_tick_size(2)
            .set_thickness(axis_thickness)
            .draw(display)?;

        Axis::new(self.plot.curve.y_range.clone())
            .set_title("Y")
            .set_scale(self.plot.y_scale)
            .into_drawable_axis(Placement::Y { y1: self.top_left.y, y2: self.bottom_right.y, x: self.top_left.x })
            .set_color(axis_color)
            .set_text_style(text_style)
            .set_tick_size(2)
            .set_thickness(axis_thickness)
            .draw(display)?;

        self.plot.curve.into_drawable_curve(
            &self.top_left,
            &self.bottom_right,
        ).set_color(color)
            .set_thickness(thickness)
            .draw(display)?;
        Ok(())
    }
}