// // This is an abstraction over a drawing environment. // // Georg Hopp // // Copyright © 2019 Georg Hopp // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // use std::cmp; use std::fmt::{Formatter, Display, Result}; use std::sync::mpsc; pub trait Easel { //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>; } pub trait Canvas { fn init_events(&self); fn start_events(&self, tx :mpsc::Sender); fn width(&self) -> u16; fn height(&self) -> u16; fn clear(&mut self); fn draw(&mut self, c :&dyn Drawable, ofs :Coordinate, color :u32); fn put_text(&self, ofs :Coordinate, s :&str); fn show(&self); } pub trait Drawable { fn plot(&self) -> Coordinates; } #[derive(Debug, Clone, Copy)] pub struct Coordinate(pub i32, pub i32); #[derive(Debug, Clone)] pub struct Coordinates(pub Vec); impl Coordinate { // Tail recursive Bresenham line with integer incremental error. fn line(self, b :&Self) -> Vec { fn inner( v :&mut [Coordinate] , bx :i32, by :i32 , dx :i32, dy :i32 , sx :i32, sy :i32 , err :i32) { let Coordinate(x, y) = v[0]; if x != bx || y != by { let (x, y, err) = match (2*err >= dy, 2*err <= dx) { (true, false) => (x + sx, y, err + dy), (false, true) => ( x, y + sy, err + dx), _ => (x + sx, y + sy, err + dx + dy ), }; v[1] = Coordinate(x, y); inner(&mut v[1..], bx, by, dx, dy, sx, sy, err); } } let Coordinate(ax, ay) = self; let Coordinate(bx, by) = *b; let dx = (bx - ax).abs(); let sx :i32 = if ax < bx { 1 } else { -1 }; let dy = -(by - ay).abs(); let sy :i32 = if ay < by { 1 } else { -1 }; let mut v :Vec = vec!( Coordinate(0, 0) ; cmp::max(dx, -dy) as usize + 1); v[0] = Coordinate(ax, ay); inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy); v } } impl Display for Coordinate { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "<{},{}>", self.0, self.1) } } impl Display for Coordinates { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Coordinates(is) = self; let c = match is[..] { [] => String::from(""), [a] => format!("{}", a), _ => { let mut a = format!("{}", is[0]); for i in is[1..].iter() { a = a + &format!(",{}", i); } a } }; write!(f, "Coordinates[{}]", c) } } #[derive(Debug, Clone, Copy)] pub struct Point(pub Coordinate); impl Drawable for Point{ fn plot(&self) -> Coordinates { let Point(c) = *self; Coordinates(vec!(c)) } } impl Display for Point { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Point(p) = self; write!(f, "Point[{}]", p) } } #[derive(Debug, Clone, Copy)] pub struct Line(pub Coordinate, pub Coordinate); impl Drawable for Line { fn plot(&self) -> Coordinates { let Line(a, b) = *self; Coordinates(a.line(&b)) } } impl Display for Line { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Line(a, b) = self; write!(f, "Line[{},{}]", a, b) } } #[derive(Debug, Clone, Copy)] pub struct Rectangle(pub Coordinate, pub Coordinate); impl Drawable for Rectangle { fn plot(&self) -> Coordinates { let Rectangle(a, c) = *self; let Coordinate(ax, ay) = a; let Coordinate(cx, cy) = c; let b = Coordinate(cx, ay); let d = Coordinate(ax, cy); let mut r = a.line(&b); r.append(&mut b.line(&c)[1..].to_vec()); r.append(&mut c.line(&d)[1..].to_vec()); let mut i = d.line(&a); let l = i.len(); r.append(&mut i[1..l-1].to_vec()); Coordinates(r) } } impl Display for Rectangle { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Rectangle(a, b) = self; write!(f, "Rec[{},{}]", a, b) } } #[derive(Debug, Clone)] pub struct Polyline(pub Coordinates); impl Drawable for Polyline { fn plot(&self) -> Coordinates { let Polyline(Coordinates(cs)) = self; match cs[..] { [] => Coordinates(Vec::::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { let (a, b) = (cs[0], cs[1]); let mut r = a.line(&b); let mut i = b; for j in cs[2..].iter() { r.append(&mut i.line(j)[1..].to_vec()); i = *j; } Coordinates(r) }, } } } impl Display for Polyline { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polyline(a) = self; write!(f, "PLine[{}]", a) } } #[derive(Debug, Clone)] pub struct Polygon(pub Coordinates); impl Drawable for Polygon { fn plot(&self) -> Coordinates { let Polygon(Coordinates(cs)) = self; match cs[..] { [] => Coordinates(Vec::::new()), [a] => Coordinates(vec!(a)), [a, b] => Coordinates(a.line(&b)), _ => { let (a, b) = (cs[0], cs[1]); let mut r = a.line(&b); let mut i = b; for j in cs[2..].iter() { r.append(&mut i.line(j)[1..].to_vec()); i = *j; } let mut j = a.line(&i); let l = j.len(); if l > 1 { r.append(&mut j[1..l-1].to_vec()); } Coordinates(r) }, } } } impl Display for Polygon { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let Polygon(a) = self; write!(f, "Poly[{}]", a) } }