Commit b36e20a2a0e225bdaa78e396d231864e5fef6de0

Authored by Georg Hopp
1 parent ade2a66b

Add Drawable primitives

  1 +//
  2 +// This is an abstraction over a drawing environment.
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +use std::cmp;
  22 +use std::fmt::{Formatter, Display, Result};
  23 +
  24 +pub trait Easel {
  25 + fn canvas(self) -> dyn Canvas;
  26 +}
  27 +
  28 +pub trait Canvas {
  29 + fn draw(self, c :&dyn Drawable, ofs :Coordinate);
  30 +}
  31 +
  32 +pub trait Drawable {
  33 + fn plot(&self) -> Coordinates;
  34 +}
  35 +
  36 +#[derive(Debug, Clone, Copy)]
  37 +pub struct Coordinate(pub i32, pub i32);
  38 +
  39 +#[derive(Debug, Clone)]
  40 +pub struct Coordinates(pub Vec<Coordinate>);
  41 +
  42 +impl Coordinate {
  43 + // Tail recursive Bresenham line with integer incremental error.
  44 + fn line(self, b :&Self) -> Vec<Self> {
  45 + fn inner( v :&mut [Coordinate]
  46 + , bx :i32, by :i32
  47 + , dx :i32, dy :i32
  48 + , sx :i32, sy :i32
  49 + , err :i32) {
  50 + let Coordinate(x, y) = v[0];
  51 +
  52 + if x != bx || y != by {
  53 + let doinc = (2*err >= dy, 2*err <= dx);
  54 + let (x, y, err) = match doinc {
  55 + (true, false) => (x + sx, y, err + dy),
  56 + (false, true) => ( x, y + sy, err + dx),
  57 + _ => (x + sx, y + sy, err + dx + dy ),
  58 + };
  59 + v[1] = Coordinate(x, y);
  60 + inner(&mut v[1..], bx, by, dx, dy, sx, sy, err);
  61 + }
  62 + }
  63 +
  64 + let Coordinate(ax, ay) = self;
  65 + let Coordinate(bx, by) = *b;
  66 +
  67 + let dx = (bx - ax).abs();
  68 + let sx :i32 = if ax < bx { 1 } else { -1 };
  69 + let dy = -(by - ay).abs();
  70 + let sy :i32 = if ay < by { 1 } else { -1 };
  71 +
  72 + let mut v :Vec<Self> = vec!( Coordinate(0, 0)
  73 + ; cmp::max(dx, -dy) as usize + 1);
  74 + v[0] = Coordinate(ax, ay);
  75 + inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy);
  76 + v
  77 + }
  78 +}
  79 +
  80 +impl Display for Coordinate {
  81 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  82 + write!(f, "<{},{}>", self.0, self.1)
  83 + }
  84 +}
  85 +
  86 +impl Display for Coordinates {
  87 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  88 + let Coordinates(is) = self;
  89 +
  90 + let c = match is[..] {
  91 + [] => String::from(""),
  92 + [a] => format!("{}", a),
  93 + _ => {
  94 + let mut a = format!("{}", is[0]);
  95 + for i in is[1..].iter() {
  96 + a = a + &format!(",{}", i);
  97 + }
  98 + a
  99 + }
  100 + };
  101 +
  102 + write!(f, "Coordinates[{}]", c)
  103 + }
  104 +}
  105 +
  106 +
  107 +#[derive(Debug, Clone, Copy)]
  108 +pub struct Point(pub Coordinate);
  109 +
  110 +impl Drawable for Point{
  111 + fn plot(&self) -> Coordinates {
  112 + let Point(c) = *self;
  113 + Coordinates(vec!(c))
  114 + }
  115 +}
  116 +
  117 +impl Display for Point {
  118 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  119 + let Point(p) = self;
  120 + write!(f, "Point[{}]", p)
  121 + }
  122 +}
  123 +
  124 +#[derive(Debug, Clone, Copy)]
  125 +pub struct Line(pub Coordinate, pub Coordinate);
  126 +
  127 +impl Drawable for Line {
  128 + fn plot(&self) -> Coordinates {
  129 + let Line(a, b) = *self;
  130 + Coordinates(a.line(&b))
  131 + }
  132 +}
  133 +
  134 +impl Display for Line {
  135 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  136 + let Line(a, b) = self;
  137 + write!(f, "Line[{},{}]", a, b)
  138 + }
  139 +}
  140 +
  141 +#[derive(Debug, Clone, Copy)]
  142 +pub struct Rectangle(pub Coordinate, pub Coordinate);
  143 +
  144 +impl Drawable for Rectangle {
  145 + fn plot(&self) -> Coordinates {
  146 + let Rectangle(a, c) = *self;
  147 + let Coordinate(ax, ay) = a;
  148 + let Coordinate(cx, cy) = c;
  149 + let b = Coordinate(cx, ay);
  150 + let d = Coordinate(ax, cy);
  151 +
  152 + let mut r = a.line(&b);
  153 + r.append(&mut b.line(&c)[1..].to_vec());
  154 + r.append(&mut c.line(&d)[1..].to_vec());
  155 + let mut i = d.line(&a);
  156 + let l = i.len();
  157 + r.append(&mut i[1..l-1].to_vec());
  158 +
  159 + Coordinates(r)
  160 + }
  161 +}
  162 +
  163 +impl Display for Rectangle {
  164 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  165 + let Rectangle(a, b) = self;
  166 + write!(f, "Rec[{},{}]", a, b)
  167 + }
  168 +}
  169 +
  170 +#[derive(Debug, Clone)]
  171 +pub struct Polyline(pub Coordinates);
  172 +
  173 +impl Drawable for Polyline {
  174 + fn plot(&self) -> Coordinates {
  175 + let Polyline(Coordinates(cs)) = self;
  176 +
  177 + match cs[..] {
  178 + [] => Coordinates(Vec::<Coordinate>::new()),
  179 + [a] => Coordinates(vec!(a)),
  180 + [a, b] => Coordinates(a.line(&b)),
  181 + _ => {
  182 + let (a, b) = (cs[0], cs[1]);
  183 + let mut r = a.line(&b);
  184 + let mut i = b;
  185 + for j in cs[2..].iter() {
  186 + r.append(&mut i.line(j)[1..].to_vec());
  187 + i = *j;
  188 + }
  189 + Coordinates(r)
  190 + },
  191 + }
  192 + }
  193 +}
  194 +
  195 +impl Display for Polyline {
  196 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  197 + let Polyline(a) = self;
  198 + write!(f, "PLine[{}]", a)
  199 + }
  200 +}
  201 +
  202 +#[derive(Debug, Clone)]
  203 +pub struct Polygon(pub Coordinates);
  204 +
  205 +impl Drawable for Polygon {
  206 + fn plot(&self) -> Coordinates {
  207 + let Polygon(Coordinates(cs)) = self;
  208 +
  209 + match cs[..] {
  210 + [] => Coordinates(Vec::<Coordinate>::new()),
  211 + [a] => Coordinates(vec!(a)),
  212 + [a, b] => Coordinates(a.line(&b)),
  213 + _ => {
  214 + let (a, b) = (cs[0], cs[1]);
  215 + let mut r = a.line(&b);
  216 + let mut i = b;
  217 + for j in cs[2..].iter() {
  218 + r.append(&mut i.line(j)[1..].to_vec());
  219 + i = *j;
  220 + }
  221 + let mut j = i.line(&a);
  222 + let l = j.len();
  223 + r.append(&mut j[1..l-1].to_vec());
  224 + Coordinates(r)
  225 + },
  226 + }
  227 + }
  228 +}
  229 +
  230 +impl Display for Polygon {
  231 + fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  232 + let Polygon(a) = self;
  233 + write!(f, "Poly[{}]", a)
  234 + }
  235 +}
@@ -23,6 +23,7 @@ extern crate lazy_static; @@ -23,6 +23,7 @@ extern crate lazy_static;
23 pub type Error = &'static str; 23 pub type Error = &'static str;
24 24
25 pub mod continuous; 25 pub mod continuous;
  26 +pub mod easel;
26 pub mod fractional; 27 pub mod fractional;
27 pub mod transform; 28 pub mod transform;
28 pub mod trigonometry; 29 pub mod trigonometry;
@@ -18,7 +18,6 @@ @@ -18,7 +18,6 @@
18 // You should have received a copy of the GNU General Public License 18 // You should have received a copy of the GNU General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>. 19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 // 20 //
21 -use std::cmp;  
22 use std::convert::{TryFrom, TryInto, Into}; 21 use std::convert::{TryFrom, TryInto, Into};
23 use std::f64::consts::PI as FPI; 22 use std::f64::consts::PI as FPI;
24 use std::fmt::Display; 23 use std::fmt::Display;
@@ -26,47 +25,13 @@ use std::num::TryFromIntError; @@ -26,47 +25,13 @@ use std::num::TryFromIntError;
26 use std::ops::{Add,Sub,Neg,Mul,Div}; 25 use std::ops::{Add,Sub,Neg,Mul,Div};
27 26
28 use fractional::continuous::Continuous; 27 use fractional::continuous::Continuous;
  28 +use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
  29 + , Polygon, Rectangle};
29 use fractional::fractional::{Fractional, from_vector}; 30 use fractional::fractional::{Fractional, from_vector};
30 use fractional::trigonometry::Trig; 31 use fractional::trigonometry::Trig;
31 use fractional::vector::{Vector}; 32 use fractional::vector::{Vector};
32 use fractional::transform::{TMatrix, translate, rotate_x, rotate_y, rotate_z, rotate_v}; 33 use fractional::transform::{TMatrix, translate, rotate_x, rotate_y, rotate_z, rotate_v};
33 34
34 -// Tail recursive Bresenham line with integer incremental error.  
35 -fn line(a :(u32, u32), b :(u32, u32)) -> Vec<(u32, u32)>{  
36 - fn inner( v :&mut [(u32, u32)]  
37 - , bx :u32, by :u32  
38 - , dx :i32, dy :i32  
39 - , sx :i32, sy :i32  
40 - , err :i32) {  
41 - let (x, y) = v[0];  
42 -  
43 - if x != bx || y != by {  
44 - let (x, y, err) = match (2*err as i32 >= dy, 2*err as i32 <= dx) {  
45 - (true, false) => ((x as i32 + sx) as u32, y, err + dy),  
46 - (false, true) => (x, (y as i32 + sy) as u32, err + dx),  
47 - _ => ( (x as i32 + sx) as u32  
48 - , (y as i32 + sy) as u32  
49 - , err + dx + dy ),  
50 - };  
51 - v[1] = (x, y);  
52 - inner(&mut v[1..], bx, by, dx, dy, sx, sy, err);  
53 - }  
54 - }  
55 -  
56 - let (ax, ay) = a;  
57 - let (bx, by) = b;  
58 -  
59 - let dx = (bx as i32 - ax as i32).abs();  
60 - let sx :i32 = if ax < bx { 1 } else { -1 };  
61 - let dy = -(by as i32 - ay as i32).abs();  
62 - let sy :i32 = if ay < by { 1 } else { -1 };  
63 -  
64 - let mut v :Vec<(u32, u32)> = vec!((0, 0); cmp::max(dx, -dy) as usize + 1);  
65 - v[0] = (ax, ay);  
66 - inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy);  
67 - v  
68 -}  
69 -  
70 fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> { 35 fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
71 let r = v.iter().fold(0, |acc, x| acc + x); 36 let r = v.iter().fold(0, |acc, x| acc + x);
72 let l = i64::try_from(v.len())?; 37 let l = i64::try_from(v.len())?;
@@ -268,14 +233,31 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) @@ -268,14 +233,31 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
268 } 233 }
269 234
270 fn _line() { 235 fn _line() {
271 - println!("{:>14} : {:?}", "Line", line((0,1), (6,4)));  
272 - println!("{:>14} : {:?}", "Line", line((0,4), (6,1)));  
273 - println!("{:>14} : {:?}", "Line", line((6,1), (0,4)));  
274 - println!("{:>14} : {:?}", "Line", line((6,4), (0,1)));  
275 - println!("{:>14} : {:?}", "Line", line((0,1), (6,8)));  
276 - println!("{:>14} : {:?}", "Line", line((0,8), (6,1)));  
277 - println!("{:>14} : {:?}", "Line", line((6,1), (0,8)));  
278 - println!("{:>14} : {:?}", "Line", line((6,8), (0,1))); 236 + let a = (Coordinate(0, 1), Coordinate(6, 4));
  237 + let b = (Coordinate(0, 4), Coordinate(6, 1));
  238 + let c = (Coordinate(1, 0), Coordinate(6, 8));
  239 + let d = (Coordinate(1, 8), Coordinate(6, 0));
  240 +
  241 + for i in [a, b, c, d].iter() {
  242 + println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot());
  243 + println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot());
  244 + }
  245 +
  246 + println!();
  247 + let r = Rectangle(Coordinate(1, 1), Coordinate(10, 5));
  248 + println!("{:>14} : {}", r, r.plot());
  249 +
  250 + println!();
  251 + let pl = Polyline(
  252 + Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1)));
  253 + println!("{:>14} : {}", pl, pl.plot());
  254 +
  255 + println!();
  256 + let pg = Polygon(
  257 + Coordinates(vec!( Coordinate( 0, -20)
  258 + , Coordinate( 20, 20)
  259 + , Coordinate(-20, 20) )));
  260 + println!("{:>14} : {}", pg, pg.plot());
279 } 261 }
280 262
281 fn main() { 263 fn main() {
Please register or login to post a comment