diff --git a/examples/free_axis.rs b/examples/free_axis.rs index 9181814..662662b 100644 --- a/examples/free_axis.rs +++ b/examples/free_axis.rs @@ -26,40 +26,101 @@ fn main() -> Result<(), core::convert::Infallible> { .text_color(RgbColor::YELLOW) .build(); - Axis::new("X Fixed 0-100(10)", Placement::X{x1: 40, x2: 230, y: 10}, 0..100, Scale::Fixed(10), RgbColor::WHITE, text_style_white, 2) + 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 + ) .draw(&mut display)?; - Axis::new("X Fixed 0-200(100)", Placement::X{x1: 240, x2: 470, y: 10}, 0..200, Scale::Fixed(100), RgbColor::YELLOW, text_style_yellow_compact, 1) + 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 + ) .draw(&mut display)?; - Axis::new("X Frac 0-100(7)", Placement::X{x1: 50, x2: 220, y: 30}, 0..100, Scale::RangeFraction(7), RgbColor::BLUE, text_style_white, 3) + 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 + ) .draw(&mut display)?; - Axis::new("X Frac 0-200(4)", Placement::X{x1: 250, x2: 460, y: 40}, 0..200, Scale::RangeFraction(4), RgbColor::RED, text_style_yellow_compact, 7) + 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 + ) .draw(&mut display)?; - Axis::new("Y Fixed 0-100(10)", Placement::Y{y1: 70, y2: 230, x: 160}, 0..100, Scale::Fixed(10), RgbColor::WHITE, text_style_white, 2) + Axis::new("Y Fixed 0-100(10)", 0..100, Scale::Fixed(10)) + .into_drawable_axis( + Placement::Y{y1: 70, y2: 230, x: 160}, + RgbColor::WHITE, + text_style_white, + 2 + ) .draw(&mut display)?; - Axis::new("Y Fixed 0-200(100)", Placement::Y{y1: 70, y2: 210, x: 260}, 0..200, Scale::Fixed(100), RgbColor::YELLOW, text_style_yellow_compact, 1) + Axis::new("Y Fixed 0-200(100)", 0..200, Scale::Fixed(100)) + .into_drawable_axis( + Placement::Y{y1: 70, y2: 210, x: 260}, + RgbColor::YELLOW, + text_style_yellow_compact, + 1 + ) .draw(&mut display)?; - Axis::new("Y Frac 0-100(7)", Placement::Y{y1: 60, y2: 180, x: 370}, 0..100, Scale::RangeFraction(7), RgbColor::BLUE, text_style_white, 3) + 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 + ) .draw(&mut display)?; - Axis::new("Y Frac 0-200(4)", Placement::Y{y1: 90, y2: 220, x: 470}, 0..200, Scale::RangeFraction(4), RgbColor::RED, text_style_yellow_compact, 7) + 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 + ) .draw(&mut display)?; - Axis::new("X", Placement::X{x1: 30, x2: 470, y: 250}, 123..2137, Scale::Fixed(150), RgbColor::YELLOW, text_style_white, 2) + 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 + ) .draw(&mut display)?; - Axis::new("Y", Placement::Y{y1: 10, y2: 250, x: 30}, 0..2137, Scale::RangeFraction(15), RgbColor::WHITE, text_style_white, 2) + + 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 + ) .draw(&mut display)?; let output_settings = OutputSettingsBuilder::new() .pixel_spacing(1) .build(); - Window::new("Basic plot", &output_settings).show_static(&display); + Window::new("Free axis", &output_settings).show_static(&display); Ok(()) } \ No newline at end of file diff --git a/examples/single_plot_mono.rs b/examples/single_plot_mono.rs index 6796886..803ab3e 100644 --- a/examples/single_plot_mono.rs +++ b/examples/single_plot_mono.rs @@ -1,5 +1,6 @@ use embedded_graphics::{ prelude::*, + pixelcolor::BinaryColor, }; use embedded_graphics_simulator::{SimulatorDisplay, Window, OutputSettingsBuilder, BinaryColorTheme}; @@ -7,21 +8,28 @@ use embedded_graphics_simulator::{SimulatorDisplay, Window, OutputSettingsBuilde use embedded_plots::{ single_plot::{SinglePlot}, curve::{PlotPoint, Curve}, + axis::Scale, }; -use embedded_graphics::pixelcolor::BinaryColor; fn main() -> Result<(), core::convert::Infallible> { let mut display: SimulatorDisplay = SimulatorDisplay::new(Size::new(128, 48)); let data = vec![ PlotPoint { x: 0, y: 0 }, - PlotPoint { x: 1, y: 1 }, - PlotPoint { x: 2, y: 1 }, + PlotPoint { x: 1, y: 2 }, + PlotPoint { x: 2, y: 2 }, PlotPoint { x: 3, y: 0 }, ]; let curve = Curve::from_data(data.as_slice()); - let plot = SinglePlot::new(&curve, BinaryColor::On, Point { x: 9, y: 3 }, Point { x: 120, y: 45 }); + let plot = SinglePlot::new( + &curve, + BinaryColor::On, + Point { x: 9, y: 3 }, + Point { x: 120, y: 45 }, + Scale::RangeFraction(3), + Scale::RangeFraction(2) + ); plot.draw(&mut display)?; let output_settings = OutputSettingsBuilder::new() diff --git a/examples/single_plot_rgb.rs b/examples/single_plot_rgb.rs index d413c68..922d16b 100644 --- a/examples/single_plot_rgb.rs +++ b/examples/single_plot_rgb.rs @@ -13,6 +13,7 @@ use embedded_graphics_simulator::{ use embedded_plots::{ single_plot::{SinglePlot}, curve::{PlotPoint, Curve}, + axis::Scale, }; fn main() -> Result<(), core::convert::Infallible> { @@ -20,13 +21,20 @@ fn main() -> Result<(), core::convert::Infallible> { let data = vec![ PlotPoint { x: 0, y: 0 }, - PlotPoint { x: 1, y: 1 }, - PlotPoint { x: 2, y: 1 }, + PlotPoint { x: 1, y: 2 }, + PlotPoint { x: 2, y: 2 }, PlotPoint { x: 3, y: 0 }, ]; let curve = Curve::from_data(data.as_slice()); - let plot = SinglePlot::new(&curve, RgbColor::YELLOW, Point { x: 50, y: 10 }, Point { x: 430, y: 250 }); + let plot = SinglePlot::new( + &curve, + RgbColor::YELLOW, + Point { x: 50, y: 10 }, + Point { x: 430, y: 250 }, + Scale::RangeFraction(3), + Scale::RangeFraction(2) + ); plot.draw(&mut display)?; let output_settings = OutputSettingsBuilder::new() diff --git a/src/axis.rs b/src/axis.rs index 629dc94..d5a1a42 100644 --- a/src/axis.rs +++ b/src/axis.rs @@ -1,13 +1,8 @@ -use embedded_graphics::primitives::Line; -use embedded_graphics::drawable::Drawable; -use embedded_graphics::DrawTarget; use core::ops::Range; use embedded_graphics::prelude::*; -use embedded_graphics::style::{PrimitiveStyle, TextStyle}; -use crate::range_conv::Scalable; -use embedded_graphics::fonts::Text; -use heapless::{consts::*, String}; -use core::fmt::Write; +use embedded_graphics::style::{TextStyle}; + +use crate::drawable_axis::DrawableAxis; pub enum Placement { X { @@ -27,97 +22,24 @@ pub enum Scale { RangeFraction(usize), } -pub struct Axis<'a, C, F> - where - C: PixelColor, - F: Font, - TextStyle: Clone, -{ +pub struct Axis<'a> { title: &'a str, - placement: Placement, range: Range, scale: Scale, - color: C, - text_style: TextStyle, - tick_size: usize, } -impl<'a, C, F> Axis<'a, C, F> - where - C: PixelColor, - F: Font, - TextStyle: Clone, +impl<'a> Axis<'a> { - pub fn new(title: &'a str, orientation: Placement, range: Range, scale: Scale, color: C, text_style: TextStyle, tick_height: usize) -> Axis<'a, C, F> { - Axis { title, placement: orientation, range, scale, color, text_style, tick_size: tick_height } + pub fn new(title: &'a str, range: Range, scale: Scale) -> Axis<'a> { + Axis{title, range, scale} } - pub fn size(&self) -> Point { - Point{x: 50, y: 50} + pub fn into_drawable_axis(self, placement: Placement, plot_color: C, text_style: TextStyle, tick_height: usize) -> DrawableAxis<'a, C, F> + where + C: PixelColor, + F: Font, + TextStyle: Clone, + { + DrawableAxis::new(self.title,placement,self.range,self.scale,plot_color,text_style,tick_height) } } - - -impl<'a, C, F> Drawable for Axis<'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, 1)) - .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, 1)) - .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, 1)) - .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, 1)) - .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/curve.rs b/src/curve.rs index a05aba9..a5f58e8 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -13,8 +13,8 @@ pub struct PlotPoint { pub struct Curve<'a> { points: &'a [PlotPoint], - x_range: Range, - y_range: Range, + pub x_range: Range, + pub y_range: Range, } impl<'a> Curve<'a> { diff --git a/src/drawable_axis.rs b/src/drawable_axis.rs new file mode 100644 index 0000000..b93359b --- /dev/null +++ b/src/drawable_axis.rs @@ -0,0 +1,105 @@ +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, +} + +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) -> DrawableAxis<'a, C, F> { + DrawableAxis { title, placement, range, scale, color, text_style, tick_size: tick_height } + } + + 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, 1)) + .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, 1)) + .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, 1)) + .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, 1)) + .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/drawable_curve.rs b/src/drawable_curve.rs index 4699bb6..4b65cf5 100644 --- a/src/drawable_curve.rs +++ b/src/drawable_curve.rs @@ -16,7 +16,7 @@ impl DrawableCurve C: PixelColor, I: Iterator, { - pub fn new(data: I, color: C) -> DrawableCurve { + pub(in crate) fn new(data: I, color: C) -> DrawableCurve { DrawableCurve { scaled_data: data, color, diff --git a/src/lib.rs b/src/lib.rs index 60972ac..a41e3cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,10 @@ #![no_std] pub mod curve; +pub mod axis; pub mod polyplot; pub mod single_plot; mod drawable_curve; mod range_conv; -pub mod axis; +mod drawable_axis; diff --git a/src/single_plot.rs b/src/single_plot.rs index 49ad5b3..e885baa 100644 --- a/src/single_plot.rs +++ b/src/single_plot.rs @@ -12,6 +12,8 @@ pub struct SinglePlot<'a, C> C: PixelColor { curve: &'a Curve<'a>, + x_scale: Scale, + y_scale: Scale, color: C, top_left: Point, bottom_right: Point, @@ -21,8 +23,8 @@ impl<'a, C> SinglePlot<'a, C> where C: PixelColor { - pub fn new(curve: &'a Curve<'a>, color: C, top_left: Point, bottom_right: Point) -> SinglePlot<'a, C> { - SinglePlot { curve, color, top_left, bottom_right} + pub fn new(curve: &'a Curve<'a>, color: C, top_left: Point, bottom_right: Point, x_scale: Scale, y_scale: Scale) -> SinglePlot<'a, C> { + SinglePlot { curve, color, top_left, bottom_right, x_scale, y_scale} } } @@ -36,10 +38,12 @@ impl<'a, C> Drawable for SinglePlot<'a, C> .text_color(self.color) .build(); - Axis::new("X", Placement::X{x1: self.top_left.x, x2: self.bottom_right.x, y: self.bottom_right.y}, 0..100, Scale::Fixed(10), self.color, text_style, 2) + Axis::new("X",self.curve.x_range.clone(),self.x_scale) + .into_drawable_axis(Placement::X{x1: self.top_left.x, x2: self.bottom_right.x, y: self.bottom_right.y},self.color,text_style,2) .draw(display)?; - Axis::new("Y", Placement::Y{y1: self.top_left.y, y2: self.bottom_right.y, x: self.top_left.x}, 0..200, Scale::Fixed(10), self.color, text_style, 1) + Axis::new("Y", self.curve.y_range.clone(), self.y_scale) + .into_drawable_axis(Placement::Y{y1: self.top_left.y, y2: self.bottom_right.y, x: self.top_left.x},self.color,text_style,2) .draw(display)?; self.curve.into_drawable_curve(