Plot scaling

This commit is contained in:
Michał Chodzikiewicz 2020-12-18 18:01:19 +01:00
parent 16838b1f31
commit 74a07353e3
4 changed files with 103 additions and 18 deletions

View file

@ -12,5 +12,5 @@ embedded-graphics = "0.6.0"
[dev-dependencies]
embedded-graphics-simulator = "0.2.1"
test-case = "1.0.0"

View file

@ -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<Rgb565> = 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()

View file

@ -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<C>(self, x_range: &Range<i32>, y_range: &Range<i32>, top_left : Point, bottom_right: Point, color: C) -> DrawableCurve<C>
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<C>
{
data: &'a [Point],
scaled_and_pos_data: Vec<Point>,
color: C,
}
impl<'a, C> Plot<'a, C>
impl<'a, C> DrawableCurve<C>
where C: PixelColor
{
pub fn new(data: &'a [Point],color : C) -> Plot<C> {
Plot {
data,
pub fn new(data: Vec<Point>,color : C) -> DrawableCurve<C> {
println!("data: {:?}",data);
DrawableCurve {
scaled_and_pos_data: data,
color,
}
}
}
impl<'a, C> Drawable<C> for Plot<'a, C>
impl<'a, C> Drawable<C> for DrawableCurve<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)?;
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(())
}

39
src/range_conv.rs Normal file
View 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)
}
}