From 76c399ac6c7b9bd4c2db6b141112f9cc1a0958b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Chodzikiewicz?= Date: Tue, 2 Mar 2021 21:18:53 +0100 Subject: [PATCH] Refactor axis to builder pattern --- examples/free_axis.rs | 149 ++++++++++++++++++-------------------- src/axis.rs | 165 +++++++++++++++++++++++++++++++++++++++--- src/drawable_axis.rs | 106 --------------------------- src/lib.rs | 3 +- src/single_plot.rs | 47 ++++++------ 5 files changed, 247 insertions(+), 223 deletions(-) delete mode 100644 src/drawable_axis.rs diff --git a/examples/free_axis.rs b/examples/free_axis.rs index 1db5319..b47b82c 100644 --- a/examples/free_axis.rs +++ b/examples/free_axis.rs @@ -26,104 +26,97 @@ fn main() -> Result<(), core::convert::Infallible> { .text_color(RgbColor::YELLOW) .build(); - Axis::new("X Fixed 0-100(10)", 0..100, Scale::Fixed(10)) - .into_drawable_axis( - Placement::X{x1: 40, x2: 230, y: 10}, - RgbColor::WHITE, - text_style_white, - 2, - 2, - ) + Axis::new(0..100) + .set_title("X Fixed 0-100(10)") + .set_scale(Scale::Fixed(10)) + .into_drawable_axis(Placement::X { x1: 40, x2: 230, y: 10 }) + .set_color(RgbColor::WHITE) + .set_text_style(text_style_white) + .set_thickness(2) + .set_tick_size(2) .draw(&mut display)?; - Axis::new("X Fixed 0-200(100)", 0..200, Scale::Fixed(100)) - .into_drawable_axis( - Placement::X{x1: 240, x2: 470, y: 10}, - RgbColor::YELLOW, - text_style_yellow_compact, - 1, - 2, - ) + Axis::new(0..200) + .set_title("X Fixed 0-200(100)") + .set_scale(Scale::Fixed(100)) + .into_drawable_axis(Placement::X { x1: 240, x2: 470, y: 10 }) + .set_color(RgbColor::YELLOW) + .set_text_style(text_style_yellow_compact) + .set_tick_size(2) .draw(&mut display)?; - Axis::new("X Frac 0-100(7)", 0..100, Scale::RangeFraction(7)) - .into_drawable_axis( - Placement::X{x1: 50, x2: 220, y: 30}, - RgbColor::BLUE, - text_style_white, - 3, - 1, - ) + Axis::new(0..100) + .set_title("X Frac 0-100(7)") + .set_scale(Scale::RangeFraction(7)) + .into_drawable_axis(Placement::X { x1: 50, x2: 220, y: 30 }) + .set_color(RgbColor::BLUE) + .set_text_style(text_style_white) + .set_tick_size(3) .draw(&mut display)?; - Axis::new("X Frac 0-200(4)", 0..200, Scale::RangeFraction(4)) - .into_drawable_axis( - Placement::X{x1: 250, x2: 460, y: 40}, - RgbColor::RED, - text_style_yellow_compact, - 7, - 1, - ) + Axis::new(0..200) + .set_title("X Frac 0-200(4)") + .set_scale(Scale::RangeFraction(4)) + .into_drawable_axis(Placement::X { x1: 250, x2: 460, y: 40 }) + .set_color(RgbColor::RED) + .set_text_style(text_style_yellow_compact) + .set_tick_size(7) .draw(&mut display)?; - Axis::new("Y Fixed 0-100(10)", 0..100, Scale::Fixed(10)) + Axis::new(0..100) + .set_title("Y Fixed 0-100(10)") + .set_scale(Scale::Fixed(10)) .into_drawable_axis( - Placement::Y{y1: 70, y2: 230, x: 160}, - RgbColor::WHITE, - text_style_white, - 2, - 1, - ) + Placement::Y { y1: 70, y2: 230, x: 160 }) + .set_color(RgbColor::WHITE) + .set_text_style(text_style_white) + .set_tick_size(2) .draw(&mut display)?; - Axis::new("Y Fixed 0-200(100)", 0..200, Scale::Fixed(100)) + Axis::new(0..200) + .set_title("Y Fixed 0-200(100)") + .set_scale(Scale::Fixed(100)) .into_drawable_axis( - Placement::Y{y1: 70, y2: 210, x: 260}, - RgbColor::YELLOW, - text_style_yellow_compact, - 1, - 1, - ) + Placement::Y { y1: 70, y2: 210, x: 260 }) + .set_color(RgbColor::YELLOW) + .set_text_style(text_style_yellow_compact) + .set_tick_size(1) .draw(&mut display)?; - Axis::new("Y Frac 0-100(7)", 0..100, Scale::RangeFraction(7)) - .into_drawable_axis( - Placement::Y{y1: 60, y2: 180, x: 370}, - RgbColor::BLUE, - text_style_white, - 3, - 1, - ) + Axis::new(0..100) + .set_title("Y Frac 0-100(7)") + .set_scale(Scale::RangeFraction(7)) + .into_drawable_axis(Placement::Y { y1: 60, y2: 180, x: 370 }) + .set_color(RgbColor::BLUE) + .set_text_style(text_style_white) + .set_tick_size(3) .draw(&mut display)?; - Axis::new("Y Frac 0-200(4)", 0..200, Scale::RangeFraction(4)) - .into_drawable_axis( - Placement::Y{y1: 90, y2: 220, x: 470}, - RgbColor::RED, - text_style_yellow_compact, - 7, - 1, - ) + Axis::new(0..200) + .set_title("Y Frac 0-200(4)") + .set_scale(Scale::RangeFraction(4)) + .into_drawable_axis(Placement::Y { y1: 90, y2: 220, x: 470 }) + .set_color(RgbColor::RED) + .set_text_style(text_style_yellow_compact) + .set_tick_size(7) .draw(&mut display)?; - Axis::new("X", 123..2137, Scale::Fixed(150)) - .into_drawable_axis( - Placement::X{x1: 30, x2: 470, y: 250}, - RgbColor::YELLOW, - text_style_white, - 2, - 1, - ) + Axis::new(123..2137) + .set_title("X") + .set_scale(Scale::Fixed(150)) + .into_drawable_axis(Placement::X { x1: 30, x2: 470, y: 250 }) + .set_color(RgbColor::YELLOW) + .set_text_style(text_style_white) + .set_tick_size(2) .draw(&mut display)?; - Axis::new("Y", 0..2137, Scale::RangeFraction(15)) - .into_drawable_axis( - Placement::Y{y1: 10, y2: 250, x: 30}, - RgbColor::WHITE, - text_style_white, - 2, - 1, - ) + Axis::new(0..2137) + .set_title("Y") + .set_scale(Scale::RangeFraction(15)) + .into_drawable_axis(Placement::Y { y1: 10, y2: 250, x: 30 }) + .set_color(RgbColor::WHITE) + .set_text_style(text_style_white) + .set_tick_size(2) .draw(&mut display)?; diff --git a/src/axis.rs b/src/axis.rs index bf71e42..f3e8ab3 100644 --- a/src/axis.rs +++ b/src/axis.rs @@ -1,8 +1,15 @@ use core::ops::Range; -use embedded_graphics::prelude::*; -use embedded_graphics::style::{TextStyle}; +use core::fmt::Write; +use heapless::{consts::*, String}; + +use embedded_graphics::{ + prelude::*, + style::{TextStyle, PrimitiveStyle}, + primitives::Line, + fonts::Text, +}; +use crate::range_conv::Scalable; -use crate::drawable_axis::DrawableAxis; pub enum Placement { X { @@ -22,24 +29,160 @@ pub enum Scale { RangeFraction(usize), } +impl Default for Scale { + fn default() -> Self { + Scale::RangeFraction(5) + } +} + pub struct Axis<'a> { - title: &'a str, range: Range, - scale: Scale, + title: Option<&'a str>, + scale: Option, } impl<'a> Axis<'a> { - pub fn new(title: &'a str, range: Range, scale: Scale) -> Axis<'a> { - Axis{title, range, scale} + pub fn new(range: Range) -> Axis<'a> { + Axis { range, title: None, scale: None } } - pub fn into_drawable_axis(self, placement: Placement, plot_color: C, text_style: TextStyle, tick_height: usize, thickness: usize) -> DrawableAxis<'a, C, F> + pub fn set_scale(mut self, scale: Scale) -> Axis<'a> { + self.scale = Some(scale); + self + } + + pub fn set_title(mut self, title: &'a str) -> Axis<'a> { + self.title = Some(title); + self + } + + pub fn into_drawable_axis(self, placement: Placement) -> DrawableAxis<'a, C, F> where - C: PixelColor, + C: PixelColor + Default, F: Font, - TextStyle: Clone, + TextStyle: Clone + Default, { - DrawableAxis::new(self.title,placement,self.range,self.scale,plot_color,text_style,tick_height,thickness) + DrawableAxis{ + axis: self, + placement, + color: None, + text_style: None, + tick_size: None, + thickness: None, + } } } + +pub struct DrawableAxis<'a, C, F> + where + C: PixelColor, + F: Font, + TextStyle: Clone + Default, +{ + axis: Axis<'a>, + placement: Placement, + color: Option, + text_style: Option>, + tick_size: Option, + thickness: Option, +} + +impl<'a, C, F> DrawableAxis<'a, C, F> + where + C: PixelColor + Default, + F: Font, + TextStyle: Clone + Default, +{ + pub fn set_color(mut self, val: C) -> DrawableAxis<'a, C, F> { + self.color = Some(val); + self + } + pub fn set_text_style(mut self, val: TextStyle) -> DrawableAxis<'a, C, F> { + self.text_style = Some(val); + self + } + pub fn set_tick_size(mut self, val: usize) -> DrawableAxis<'a, C, F> { + self.tick_size = Some(val); + self + } + pub fn set_thickness(mut self, val: usize) -> DrawableAxis<'a, C, F> { + self.thickness = Some(val); + self + } +} + + +impl<'a, C, F> Drawable for DrawableAxis<'a, C, F> + where + C: PixelColor + Default, + F: Font + Copy, + TextStyle: Clone + Default, +{ + fn draw>(self, display: &mut D) -> Result<(), D::Error> { + let color = self.color.unwrap_or_default(); + let text_style = self.text_style.unwrap_or_default(); + let thickness = self.thickness.unwrap_or(1); + let tick_size = self.tick_size.unwrap_or(2); + + + let scale_marks = match self.axis.scale.unwrap_or_default() { + Scale::Fixed(interval) => { + self.axis.range.clone().into_iter().step_by(interval) + } + Scale::RangeFraction(fraction) => { + let len = self.axis.range.len(); + self.axis.range.clone().into_iter().step_by(len / fraction) + } + }; + match self.placement { + Placement::X { x1, x2, y } => { + Line { start: Point { x: x1, y }, end: Point { x: x2, y } } + .into_styled(PrimitiveStyle::with_stroke(color, thickness as u32)) + .draw(display)?; + if let Some(title) = self.axis.title { + let title = Text::new(title, Point { x: x1, y: y + 10 }) + .into_styled(text_style); + let title = title.translate(Point { x: (x2 - x1) / 2 - title.size().width as i32 / 2, y: 0 }); + title.draw(display)?; + } + + for mark in scale_marks { + let x = mark.scale_between_ranges(&self.axis.range, &(x1..x2)); + Line { start: Point { x, y: y - tick_size as i32 }, end: Point { x, y: y + tick_size as i32 } } + .into_styled(PrimitiveStyle::with_stroke(color, thickness as u32)) + .draw(display)?; + let mut buf: String:: = String::new(); + write!(buf, "{}", mark).unwrap(); + Text::new(&buf, Point { x: x + 2, y: y + 2 }).into_styled(text_style).draw(display)?; + } + } + Placement::Y { y1, y2, x } => { + Line { start: Point { x, y: y1 }, end: Point { x, y: y2 } } + .into_styled(PrimitiveStyle::with_stroke(color, thickness as u32)) + .draw(display)?; + + let mut max_tick_text_width = 0; + for mark in scale_marks { + let y = mark.scale_between_ranges(&self.axis.range, &(y2..y1)); + Line { start: Point { x: x - tick_size as i32, y }, end: Point { x: x + tick_size as i32, y } } + .into_styled(PrimitiveStyle::with_stroke(color, thickness as u32)) + .draw(display)?; + let mut buf: String:: = String::new(); + write!(buf, "{}", mark).unwrap(); + let tick_val = Text::new(&buf, Point { x, y }).into_styled(text_style); + let tick_val = tick_val.translate(Point { x: -(tick_val.size().width as i32) - 2, y: 2 }); + if tick_val.size().width > max_tick_text_width { max_tick_text_width = tick_val.size().width } + tick_val.draw(display)?; + } + if let Some(title) = self.axis.title { + let title = Text::new(title, Point { x, y: y1 }) + .into_styled(text_style); + let title = title.translate(Point { x: -(title.size().width as i32) - max_tick_text_width as i32 - tick_size as i32 - 2, y: (y2 - y1) / 2 }); + title.draw(display)?; + } + } + } + Ok(()) + } +} \ No newline at end of file diff --git a/src/drawable_axis.rs b/src/drawable_axis.rs deleted file mode 100644 index 48e18fc..0000000 --- a/src/drawable_axis.rs +++ /dev/null @@ -1,106 +0,0 @@ -use embedded_graphics::prelude::*; -use crate::axis::{Placement, Scale}; -use core::ops::Range; -use embedded_graphics::style::{TextStyle, PrimitiveStyle}; -use embedded_graphics::fonts::Text; -use crate::range_conv::Scalable; -use embedded_graphics::primitives::Line; -use heapless::{consts::*, String}; -use core::fmt::Write; - - -pub struct DrawableAxis<'a, C, F> - where - C: PixelColor, - F: Font, - TextStyle: Clone, -{ - title: &'a str, - placement: Placement, - range: Range, - scale: Scale, - color: C, - text_style: TextStyle, - tick_size: usize, - thickness: usize, -} - -impl<'a, C, F> DrawableAxis<'a, C, F> - where - C: PixelColor, - F: Font, - TextStyle: Clone, -{ - pub(in crate) fn new(title: &'a str, placement: Placement, range: Range, scale: Scale, color: C, text_style: TextStyle, tick_height: usize, thickness: usize) -> DrawableAxis<'a, C, F> { - DrawableAxis { title, placement, range, scale, color, text_style, tick_size: tick_height, thickness } - } - - pub fn size(&self) -> Point { - Point { x: 50, y: 50 } - } -} - - -impl<'a, C, F> Drawable for DrawableAxis<'a, C, F> - where - C: PixelColor, - F: Font + Copy, - TextStyle: Clone, -{ - fn draw>(self, display: &mut D) -> Result<(), D::Error> { - let scale_marks = match self.scale { - Scale::Fixed(interval) => { - self.range.clone().into_iter().step_by(interval) - } - Scale::RangeFraction(fraction) => { - let len = self.range.len(); - self.range.clone().into_iter().step_by(len / fraction) - } - }; - match self.placement { - Placement::X { x1, x2, y } => { - Line { start: Point { x: x1, y }, end: Point { x: x2, y } } - .into_styled(PrimitiveStyle::with_stroke(self.color, self.thickness as u32)) - .draw(display)?; - let title = Text::new(self.title, Point { x: x1, y: y + 10 }) - .into_styled(self.text_style); - let title = title.translate(Point { x: (x2 - x1) / 2 - title.size().width as i32 / 2, y: 0 }); - title.draw(display)?; - - for mark in scale_marks { - let x = mark.scale_between_ranges(&self.range, &(x1..x2)); - Line { start: Point { x, y: y - self.tick_size as i32 }, end: Point { x, y: y + self.tick_size as i32 } } - .into_styled(PrimitiveStyle::with_stroke(self.color, self.thickness as u32)) - .draw(display)?; - let mut buf: String:: = String::new(); - write!(buf, "{}", mark).unwrap(); - Text::new(&buf, Point { x: x + 2, y: y + 2 }).into_styled(self.text_style).draw(display)?; - } - } - Placement::Y { y1, y2, x } => { - Line { start: Point { x, y: y1 }, end: Point { x, y: y2 } } - .into_styled(PrimitiveStyle::with_stroke(self.color, self.thickness as u32)) - .draw(display)?; - - let mut max_tick_text_width = 0; - for mark in scale_marks { - let y = mark.scale_between_ranges(&self.range, &(y2..y1)); - Line { start: Point { x: x - self.tick_size as i32, y }, end: Point { x: x + self.tick_size as i32, y } } - .into_styled(PrimitiveStyle::with_stroke(self.color, self.thickness as u32)) - .draw(display)?; - let mut buf: String:: = String::new(); - write!(buf, "{}", mark).unwrap(); - let tick_val = Text::new(&buf, Point { x, y }).into_styled(self.text_style); - let tick_val = tick_val.translate(Point { x: -(tick_val.size().width as i32) - 2, y: 2 }); - if tick_val.size().width > max_tick_text_width { max_tick_text_width = tick_val.size().width } - tick_val.draw(display)?; - } - let title = Text::new(self.title, Point { x, y: y1 }) - .into_styled(self.text_style); - let title = title.translate(Point { x: -(title.size().width as i32) - max_tick_text_width as i32 - self.tick_size as i32 - 2, y: (y2 - y1) / 2 }); - title.draw(display)?; - } - } - Ok(()) - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fafaba5..3b7e2e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,5 +5,4 @@ pub mod axis; pub mod polyplot; pub mod single_plot; -mod range_conv; -mod drawable_axis; +mod range_conv; \ No newline at end of file diff --git a/src/single_plot.rs b/src/single_plot.rs index 59b233b..58f5ddc 100644 --- a/src/single_plot.rs +++ b/src/single_plot.rs @@ -73,39 +73,34 @@ impl<'a, C> Drawable for DrawableSinglePlot<'a, C> C: PixelColor + Default, { fn draw>(self, display: &mut D) -> Result<(), D::Error> { - let color = match self.color { - None => C::default(), - Some(c) => c, - }; - let text_color = match self.text_color { - None => color, - Some(c) => c, - }; - let axis_color = match self.axis_color { - None => color, - Some(c) => c, - }; - - let thickness = match self.thickness { - None => 2, - Some(t) => t, - }; - - let axis_thickness = match self.axis_thickness { - None => thickness, - Some(t) => t, - }; + 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("X", self.plot.curve.x_range.clone(), self.plot.x_scale) - .into_drawable_axis(Placement::X { x1: self.top_left.x, x2: self.bottom_right.x, y: self.bottom_right.y }, axis_color, text_style, 2, axis_thickness) + 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("Y", self.plot.curve.y_range.clone(), self.plot.y_scale) - .into_drawable_axis(Placement::Y { y1: self.top_left.y, y2: self.bottom_right.y, x: self.top_left.x }, axis_color, text_style, 2,axis_thickness) + 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(