Single- and Poly- Plot

This commit is contained in:
Michał Chodzikiewicz 2020-12-20 12:11:06 +01:00
parent f2dcdb9b93
commit e2895dbc26
11 changed files with 307 additions and 37 deletions

View file

@ -8,7 +8,7 @@ edition = "2018"
[dependencies] [dependencies]
embedded-graphics = "0.6.0" embedded-graphics = "0.6.0"
itertools = "0.9.0"
[dev-dependencies] [dev-dependencies]
embedded-graphics-simulator = "0.2.1" embedded-graphics-simulator = "0.2.1"

50
examples/polyplot_mono.rs Normal file
View file

@ -0,0 +1,50 @@
use embedded_graphics::{
pixelcolor::BinaryColor,
prelude::*,
};
use embedded_graphics_simulator::{
SimulatorDisplay,
Window,
OutputSettingsBuilder,
BinaryColorTheme
};
use embedded_plots::{
polyplot::{PolyPlot},
curve::{PlotPoint, Curve},
};
fn main() -> Result<(), core::convert::Infallible> {
let mut display: SimulatorDisplay<BinaryColor> = SimulatorDisplay::new(Size::new(128, 48));
let data1 = vec![
PlotPoint { x: 0, y: 0 },
PlotPoint { x: 1, y: 1 },
PlotPoint { x: 2, y: 1 },
PlotPoint { x: 3, y: 0 },
];
let data2 = vec![
PlotPoint { x: 0, y: 1 },
PlotPoint { x: 1, y: 0 },
PlotPoint { x: 2, y: 3 },
PlotPoint { x: 3, y: 2 },
PlotPoint { x: 4, y: 2 },
];
let curves = vec![
(Curve::from_data(data1.as_slice()), BinaryColor::On),
(Curve::from_data(data2.as_slice()), BinaryColor::On),
];
let plot = PolyPlot::new(curves.as_slice(), Point { x: 10, y: 3 }, Point { x: 120, y: 45 });
plot.draw(&mut display)?;
let output_settings = OutputSettingsBuilder::new()
.theme(BinaryColorTheme::OledBlue)
.build();
Window::new("Basic plot", &output_settings).show_static(&display);
Ok(())
}

49
examples/polyplot_rgb.rs Normal file
View file

@ -0,0 +1,49 @@
use embedded_graphics::{
pixelcolor::Rgb565,
prelude::*,
};
use embedded_graphics_simulator::{
SimulatorDisplay,
Window,
OutputSettingsBuilder,
};
use embedded_plots::{
polyplot::{PolyPlot},
curve::{PlotPoint, Curve},
};
fn main() -> Result<(), core::convert::Infallible> {
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(480, 272));
let data1 = vec![
PlotPoint { x: 0, y: 0 },
PlotPoint { x: 1, y: 1 },
PlotPoint { x: 2, y: 1 },
PlotPoint { x: 3, y: 0 },
];
let data2 = vec![
PlotPoint { x: 0, y: 1 },
PlotPoint { x: 1, y: 0 },
PlotPoint { x: 2, y: 3 },
PlotPoint { x: 3, y: 2 },
PlotPoint { x: 4, y: 2 },
];
let curves = vec![
(Curve::from_data(data1.as_slice()), RgbColor::YELLOW),
(Curve::from_data(data2.as_slice()), RgbColor::RED),
];
let plot = PolyPlot::new(curves.as_slice(), Point { x: 10, y: 10 }, Point { x: 470, y: 260 });
plot.draw(&mut display)?;
let output_settings = OutputSettingsBuilder::new()
.build();
Window::new("Basic plot", &output_settings).show_static(&display);
Ok(())
}

View file

@ -0,0 +1,34 @@
use embedded_graphics::{
prelude::*,
};
use embedded_graphics_simulator::{SimulatorDisplay, Window, OutputSettingsBuilder, BinaryColorTheme};
use embedded_plots::{
single_plot::{SinglePlot},
curve::{PlotPoint, Curve},
};
use embedded_graphics::pixelcolor::BinaryColor;
fn main() -> Result<(), core::convert::Infallible> {
let mut display: SimulatorDisplay<BinaryColor> = 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: 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 });
plot.draw(&mut display)?;
let output_settings = OutputSettingsBuilder::new()
.theme(BinaryColorTheme::OledBlue)
.build();
Window::new("Basic plot", &output_settings)
.show_static(&display);
Ok(())
}

View file

@ -0,0 +1,37 @@
use embedded_graphics::{
pixelcolor::Rgb565,
prelude::*,
};
use embedded_graphics_simulator::{
SimulatorDisplay,
Window,
OutputSettingsBuilder,
};
use embedded_plots::{
single_plot::{SinglePlot},
curve::{PlotPoint, Curve},
};
fn main() -> Result<(), core::convert::Infallible> {
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(480, 272));
let data = vec![
PlotPoint { x: 0, y: 0 },
PlotPoint { x: 1, y: 1 },
PlotPoint { x: 2, y: 1 },
PlotPoint { x: 3, y: 0 },
];
let curve = Curve::from_data(data.as_slice());
let plot = SinglePlot::new(&curve, RgbColor::YELLOW, Point { x: 10, y: 10 }, Point { x: 470, y: 260 });
plot.draw(&mut display)?;
let output_settings = OutputSettingsBuilder::new()
.build();
Window::new("Basic plot", &output_settings).show_static(&display);
Ok(())
}

View file

@ -3,6 +3,8 @@ use core::ops::{Range};
use crate::range_conv::Scalable; use crate::range_conv::Scalable;
use crate::drawable_curve::DrawableCurve; use crate::drawable_curve::DrawableCurve;
use embedded_graphics::prelude::*; use embedded_graphics::prelude::*;
use itertools::MinMaxResult::MinMax;
use itertools::{Itertools, MinMaxResult};
pub struct PlotPoint { pub struct PlotPoint {
pub x: i32, pub x: i32,
@ -11,36 +13,55 @@ pub struct PlotPoint {
pub struct Curve<'a> { pub struct Curve<'a> {
points: &'a [PlotPoint], points: &'a [PlotPoint],
x_range: Range<i32>,
y_range: Range<i32>,
} }
impl<'a> Curve<'a> { impl<'a> Curve<'a> {
pub fn new(points: &'a [PlotPoint]) -> Curve { pub fn new(points: &'a [PlotPoint], x_range: Range<i32>, y_range: Range<i32>) -> Curve {
Curve {points} Curve { points, x_range, y_range }
} }
pub fn into_drawable_curve<C>(self, pub fn from_data(points: &'a [PlotPoint]) -> Curve {
x_range: &'a Range<i32>, let x_range = match points
y_range: &'a Range<i32>, .iter()
.map(|p| (p.x))
.minmax() {
MinMaxResult::NoElements => 0..0,
MinMaxResult::OneElement(v) => v..v,
MinMax(min, max) => min..max,
};
let y_range = match points.iter().map(|p| (p.y)).minmax() {
MinMaxResult::NoElements => 0..0,
MinMaxResult::OneElement(v) => v..v,
MinMax(min, max) => min..max,
};
Curve { points, x_range, y_range }
}
pub fn into_drawable_curve<C>(&self,
top_left: &'a Point, top_left: &'a Point,
bottom_right: &'a Point, bottom_right: &'a Point,
color: C color: C,
) -> DrawableCurve<C,impl Iterator<Item=Point> + 'a> ) -> DrawableCurve<C, impl Iterator<Item=Point> + '_>
where C: PixelColor where C: PixelColor
{ {
assert!(top_left.x < bottom_right.x); assert!(top_left.x < bottom_right.x);
assert!(top_left.y < bottom_right.y); assert!(top_left.y < bottom_right.y);
assert!(!x_range.is_empty()); assert!(!self.x_range.is_empty());
assert!(!y_range.is_empty()); assert!(!self.y_range.is_empty());
let it = self.points.iter() let it = self.points.iter()
.map(move |p| Point { .map(move |p| Point {
x: p.x.scale_between_ranges( x: p.x.scale_between_ranges(
x_range, &self.x_range,
&Range{start: top_left.x, end: bottom_right.x} &Range { start: top_left.x, end: bottom_right.x },
), ),
y: p.y.scale_between_ranges( y: p.y.scale_between_ranges(
y_range, &self.y_range,
&Range{start: bottom_right.y, end: top_left.y} &Range { start: bottom_right.y, end: top_left.y },
), ),
}); });
DrawableCurve::new(it, color) DrawableCurve::new(it, color)
@ -48,7 +69,6 @@ impl<'a> Curve<'a> {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]

View file

@ -25,11 +25,12 @@ impl<C,I> DrawableCurve<C,I>
} }
} }
} }
impl<C, I> Drawable<C> for DrawableCurve<C, I> impl<C, I> Drawable<C> for DrawableCurve<C, I>
where C: PixelColor, where C: PixelColor,
I: Iterator<Item=Point>, I: Iterator<Item=Point>,
{ {
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), <D as DrawTarget<C>>::Error> { fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), D::Error> {
let style = PrimitiveStyle::with_stroke(self.color, 2); let style = PrimitiveStyle::with_stroke(self.color, 2);
let mut iter = self.scaled_data.into_iter(); let mut iter = self.scaled_data.into_iter();
let mut prev = iter.next().unwrap(); let mut prev = iter.next().unwrap();

View file

@ -1,6 +1,8 @@
#![no_std] #![no_std]
pub mod curve; pub mod curve;
pub mod plot; pub mod polyplot;
pub mod single_plot;
mod drawable_curve; mod drawable_curve;
mod range_conv; mod range_conv;

39
src/polyplot.rs Normal file
View file

@ -0,0 +1,39 @@
use crate::curve::Curve;
use embedded_graphics::drawable::Drawable;
use embedded_graphics::DrawTarget;
use embedded_graphics::prelude::Point;
use embedded_graphics::pixelcolor::PixelColor;
pub struct PolyPlot<'a, C>
where
C: PixelColor
{
curves: &'a [(Curve<'a>, C)],
top_left: Point,
bottom_right: Point,
}
impl<'a, C> PolyPlot<'a, C>
where
C: PixelColor
{
pub fn new(curves: &'a [(Curve<'a>, C)], top_left: Point, bottom_right: Point) -> PolyPlot<C> {
PolyPlot { curves, top_left, bottom_right }
}
}
impl<'a, C> Drawable<C> for PolyPlot<'a, C>
where
C: PixelColor
{
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), D::Error> {
for (curve, color) in self.curves {
curve.into_drawable_curve(
&self.top_left,
&self.bottom_right,
*color,
).draw(display)?;
}
Ok(())
}
}

View file

@ -19,7 +19,6 @@ impl<T> Scalable<T> for T
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use core::ops::Range; use core::ops::Range;

39
src/single_plot.rs Normal file
View file

@ -0,0 +1,39 @@
use crate::curve::Curve;
use embedded_graphics::drawable::Drawable;
use embedded_graphics::DrawTarget;
use embedded_graphics::prelude::Point;
use embedded_graphics::pixelcolor::PixelColor;
pub struct SinglePlot<'a, C>
where
C: PixelColor
{
curve: &'a Curve<'a>,
color: C,
top_left: Point,
bottom_right: Point,
}
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}
}
}
impl<'a, C> Drawable<C> for SinglePlot<'a, C>
where
C: PixelColor
{
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), D::Error> {
self.curve.into_drawable_curve(
&self.top_left,
&self.bottom_right,
self.color,
).draw(display)?;
Ok(())
}
}