mirror of
https://gitlab.com/feliix42/embedded-plots.git
synced 2024-11-22 18:06:30 +00:00
Merge branch 'feature/plot-scaling' into 'master'
Feature/plot scaling See merge request mchodzikiewicz/embedded-plots!1
This commit is contained in:
commit
8523ca8215
6 changed files with 145 additions and 51 deletions
|
@ -12,5 +12,5 @@ embedded-graphics = "0.6.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
embedded-graphics-simulator = "0.2.1"
|
embedded-graphics-simulator = "0.2.1"
|
||||||
|
test-case = "1.0.0"
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,26 @@ use embedded_graphics::{
|
||||||
pixelcolor::Rgb565,
|
pixelcolor::Rgb565,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use embedded_graphics_simulator::{SimulatorDisplay, Window, OutputSettingsBuilder};
|
|
||||||
|
|
||||||
use embedded_plots::Plot;
|
use embedded_graphics_simulator::{
|
||||||
|
SimulatorDisplay,
|
||||||
|
Window,
|
||||||
|
OutputSettingsBuilder
|
||||||
|
};
|
||||||
|
|
||||||
|
use embedded_plots::curve::{PlotPoint, CurvePoints};
|
||||||
|
|
||||||
fn main() -> Result<(), core::convert::Infallible> {
|
fn main() -> Result<(), core::convert::Infallible> {
|
||||||
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(480, 272));
|
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(480, 272));
|
||||||
|
|
||||||
let data = vec![
|
let data = vec![
|
||||||
Point::new(100, 100),
|
PlotPoint{x: 0,y: 0},
|
||||||
Point::new(150, 100),
|
PlotPoint{x: 1,y: 1},
|
||||||
Point::new(200, 200)];
|
PlotPoint{x: 2,y: 1},
|
||||||
Plot::new(data.as_slice()
|
PlotPoint{x: 3,y: 0},
|
||||||
,RgbColor::GREEN)
|
];
|
||||||
|
CurvePoints::new(data.as_slice())
|
||||||
|
.into_drawable_curve(&(0..3),&(0..1),&Point{x: 20, y: 20}, &Point{x:450,y:250},RgbColor::WHITE)
|
||||||
.draw(&mut display)?;
|
.draw(&mut display)?;
|
||||||
|
|
||||||
let output_settings = OutputSettingsBuilder::new()
|
let output_settings = OutputSettingsBuilder::new()
|
||||||
|
|
46
src/curve.rs
Normal file
46
src/curve.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use core::ops::{Range};
|
||||||
|
|
||||||
|
use crate::range_conv::Scalable;
|
||||||
|
use crate::drawable_curve::DrawableCurve;
|
||||||
|
use embedded_graphics::prelude::*;
|
||||||
|
|
||||||
|
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<C>(self, x_range: &'a Range<i32>, y_range: &'a Range<i32>, top_left : &'a Point, bottom_right: &'a Point, color: C) -> DrawableCurve<C,impl Iterator<Item=Point> + 'a>
|
||||||
|
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 it = self.points.iter()
|
||||||
|
.map(move |p| Point{
|
||||||
|
x: p.x.scale_between_ranges(x_range,&Range{start: top_left.x, end: bottom_right.x}),
|
||||||
|
y: p.y.scale_between_ranges(y_range,&Range{start: bottom_right.y, end: top_left.y}),
|
||||||
|
});
|
||||||
|
DrawableCurve::new(it,color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
42
src/drawable_curve.rs
Normal file
42
src/drawable_curve.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use embedded_graphics::drawable::{Drawable, Pixel};
|
||||||
|
use embedded_graphics::DrawTarget;
|
||||||
|
use embedded_graphics::geometry::Point;
|
||||||
|
use embedded_graphics::pixelcolor::{PixelColor};
|
||||||
|
use embedded_graphics::primitives::{Line, Primitive};
|
||||||
|
use embedded_graphics::style::PrimitiveStyle;
|
||||||
|
|
||||||
|
pub struct DrawableCurve<C, I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item=Point>,
|
||||||
|
{
|
||||||
|
scaled_data: I,
|
||||||
|
color: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C,I> DrawableCurve<C,I>
|
||||||
|
where
|
||||||
|
C: PixelColor,
|
||||||
|
I: Iterator<Item=Point>,
|
||||||
|
{
|
||||||
|
pub fn new(data: I,color : C) -> DrawableCurve<C,I> {
|
||||||
|
DrawableCurve {
|
||||||
|
scaled_data: data,
|
||||||
|
color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, C,I> Drawable<C> for DrawableCurve<C,I>
|
||||||
|
where C: PixelColor,
|
||||||
|
I: Iterator<Item=Point>,
|
||||||
|
{
|
||||||
|
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), <D as DrawTarget<C>>::Error> {
|
||||||
|
let style = PrimitiveStyle::with_stroke(self.color,2);
|
||||||
|
let mut iter = self.scaled_data.into_iter();
|
||||||
|
let mut prev = iter.next().unwrap();
|
||||||
|
for point in iter {
|
||||||
|
Line::new(prev,point).into_styled(style).draw(display)?;
|
||||||
|
prev = point;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
46
src/lib.rs
46
src/lib.rs
|
@ -1,45 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
pub mod curve;
|
||||||
|
pub mod drawable_curve;
|
||||||
|
|
||||||
use embedded_graphics::drawable::{Drawable};
|
mod range_conv;
|
||||||
use embedded_graphics::DrawTarget;
|
|
||||||
use embedded_graphics::geometry::Point;
|
|
||||||
use embedded_graphics::pixelcolor::{PixelColor};
|
|
||||||
use embedded_graphics::primitives::{Line, Primitive};
|
|
||||||
use embedded_graphics::style::PrimitiveStyle;
|
|
||||||
|
|
||||||
pub struct Plot<'a, C>
|
|
||||||
{
|
|
||||||
data: &'a [Point],
|
|
||||||
color: C,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, C> Plot<'a, C>
|
|
||||||
where C: PixelColor
|
|
||||||
{
|
|
||||||
pub fn new(data: &'a [Point],color : C) -> Plot<C> {
|
|
||||||
Plot {
|
|
||||||
data,
|
|
||||||
color,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, C> Drawable<C> for Plot<'a, C>
|
|
||||||
where C: PixelColor
|
|
||||||
{
|
|
||||||
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), <D as DrawTarget<C>>::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)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
assert_eq!(2 + 2, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
39
src/range_conv.rs
Normal file
39
src/range_conv.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use core::ops::{Range, Add, Sub, Mul, Div};
|
||||||
|
|
||||||
|
pub trait Scalable<T>
|
||||||
|
where
|
||||||
|
T: Copy + Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T>,
|
||||||
|
{
|
||||||
|
fn scale_between_ranges(&self,input_range: &Range<T>, output_range: &Range<T>) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Scalable<T> for T
|
||||||
|
where
|
||||||
|
T: Copy + Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T>,
|
||||||
|
{
|
||||||
|
fn scale_between_ranges(&self, input_range: &Range<T>, output_range: &Range<T>) -> 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<i32>,out_range: Range<i32>,val: i32) -> i32 {
|
||||||
|
val.scale_between_ranges(&in_range,&out_range)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue