diff --git a/Cargo.toml b/Cargo.toml index 0ddc088..5ae3ceb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,5 +12,5 @@ embedded-graphics = "0.6.0" [dev-dependencies] embedded-graphics-simulator = "0.2.1" - +test-case = "1.0.0" diff --git a/examples/basic-plot/main.rs b/examples/basic-plot/main.rs index 2d090a2..5726c0c 100644 --- a/examples/basic-plot/main.rs +++ b/examples/basic-plot/main.rs @@ -2,19 +2,27 @@ use embedded_graphics::{ pixelcolor::Rgb565, prelude::*, }; -use embedded_graphics_simulator::{SimulatorDisplay, Window, OutputSettingsBuilder}; -use embedded_plots::Plot; +use embedded_graphics_simulator::{ + SimulatorDisplay, + Window, + OutputSettingsBuilder +}; + +use embedded_plots::{ + CurvePoints, + PlotPoint +}; fn main() -> Result<(), core::convert::Infallible> { let mut display: SimulatorDisplay = SimulatorDisplay::new(Size::new(480, 272)); let data = vec![ - Point::new(100, 100), - Point::new(150, 100), - Point::new(200, 200)]; - Plot::new(data.as_slice() - ,RgbColor::GREEN) + PlotPoint{x: 100,y: 100}, + PlotPoint{x: 150,y: 100}, + PlotPoint{x: 200,y: 200}]; + CurvePoints::new(data.as_slice()) + .into_drawable_curve(&(100..200),&(100..200),Point{x: 00, y: 0}, Point{x:480,y:272},RgbColor::WHITE) .draw(&mut display)?; let output_settings = OutputSettingsBuilder::new() diff --git a/src/lib.rs b/src/lib.rs index afd3ccd..61ddc8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ -#![no_std] +// #![no_std] + +mod range_conv; use embedded_graphics::drawable::{Drawable}; use embedded_graphics::DrawTarget; @@ -7,30 +9,66 @@ use embedded_graphics::pixelcolor::{PixelColor}; use embedded_graphics::primitives::{Line, Primitive}; use embedded_graphics::style::PrimitiveStyle; -pub struct Plot<'a, C> +use crate::range_conv::Scalable; +use core::ops::{Range}; + +pub struct PlotPoint { + pub x: i32, + pub y: i32, +} + +pub struct CurvePoints<'a>{ + points: &'a [PlotPoint], +} + +impl<'a> CurvePoints<'a> { + pub fn new(points: &'a [PlotPoint]) -> CurvePoints { + CurvePoints{points} + } + + pub fn into_drawable_curve(self, x_range: &Range, y_range: &Range, top_left : Point, bottom_right: Point, color: C) -> DrawableCurve + where C: PixelColor + { + assert!(top_left.x < bottom_right.x); + assert!(top_left.y < bottom_right.y); + assert!(!x_range.is_empty()); + assert!(!y_range.is_empty()); + + let vec = self.points.iter() + .map(|p| Point{ + x: p.x.scale_between_ranges(x_range,&Range{start: top_left.x.into(), end: bottom_right.x.into()}).into(), + y: p.y.scale_between_ranges(y_range,&Range{start: top_left.y.into(), end: bottom_right.y.into()}).into(), + }) + .collect(); + DrawableCurve::new(vec,color) + } +} + +pub struct DrawableCurve { - data: &'a [Point], + scaled_and_pos_data: Vec, color: C, } -impl<'a, C> Plot<'a, C> +impl<'a, C> DrawableCurve where C: PixelColor { - pub fn new(data: &'a [Point],color : C) -> Plot { - Plot { - data, + pub fn new(data: Vec,color : C) -> DrawableCurve { + println!("data: {:?}",data); + DrawableCurve { + scaled_and_pos_data: data, color, } } } -impl<'a, C> Drawable for Plot<'a, C> +impl<'a, C> Drawable for DrawableCurve where C: PixelColor { fn draw>(self, display: &mut D) -> Result<(), >::Error> { let style = PrimitiveStyle::with_stroke(self.color,2); - for i in 1..self.data.len() { - Line::new(self.data[i-1],self.data[i]).into_styled(style).draw(display)?; + for i in 1..self.scaled_and_pos_data.len() { + Line::new(self.scaled_and_pos_data[i-1],self.scaled_and_pos_data[i]).into_styled(style).draw(display)?; } Ok(()) } diff --git a/src/range_conv.rs b/src/range_conv.rs new file mode 100644 index 0000000..e30c8e2 --- /dev/null +++ b/src/range_conv.rs @@ -0,0 +1,39 @@ +use core::ops::{Range, Add, Sub, Mul, Div}; + +pub trait Scalable + where + T: Copy + Add + Sub + Mul + Div, +{ + fn scale_between_ranges(&self,input_range: &Range, output_range: &Range) -> T; +} + +impl Scalable for T + where + T: Copy + Add + Sub + Mul + Div, +{ + fn scale_between_ranges(&self, input_range: &Range, output_range: &Range) -> T + { + (*self - input_range.start) * (output_range.end - output_range.start) + / (input_range.end - input_range.start) + output_range.start + } +} + + + +#[cfg(test)] +mod tests { + use core::ops::Range; + use test_case::test_case; + use crate::range_conv::Scalable; + + #[test_case(0..10,0..10,5 => 5 ; "equal ranges")] + #[test_case(0..10,0..20,5 => 10 ; "double")] + #[test_case(0..20,0..10,10 => 5 ; "half")] + #[test_case(-20..20,0..10,0 => 5 ; "negative input range")] + #[test_case(0..10,-20..20,5 => 0 ; "negative output range")] + #[test_case(0..10,10..0,2 => 8 ; "reversing")] + #[test_case(-20..20,0..20,-10 => 5 ; "reversing negative range")] + fn convert(in_range: Range,out_range: Range,val: i32) -> i32 { + val.scale_between_ranges(&in_range,&out_range) + } +}