3 changed files with 263 additions and 45 deletions
@ -0,0 +1,235 @@ |
|||||
|
//
|
||||
|
// This is an abstraction over a drawing environment.
|
||||
|
//
|
||||
|
// Georg Hopp <georg@steffers.org>
|
||||
|
//
|
||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
//
|
||||
|
use std::cmp;
|
||||
|
use std::fmt::{Formatter, Display, Result};
|
||||
|
|
||||
|
pub trait Easel {
|
||||
|
fn canvas(self) -> dyn Canvas;
|
||||
|
}
|
||||
|
|
||||
|
pub trait Canvas {
|
||||
|
fn draw(self, c :&dyn Drawable, ofs :Coordinate);
|
||||
|
}
|
||||
|
|
||||
|
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<Coordinate>);
|
||||
|
|
||||
|
impl Coordinate {
|
||||
|
// Tail recursive Bresenham line with integer incremental error.
|
||||
|
fn line(self, b :&Self) -> Vec<Self> {
|
||||
|
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 doinc = (2*err >= dy, 2*err <= dx);
|
||||
|
let (x, y, err) = match doinc {
|
||||
|
(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<Self> = 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::<Coordinate>::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::<Coordinate>::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 = i.line(&a);
|
||||
|
let l = j.len();
|
||||
|
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)
|
||||
|
}
|
||||
|
}
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue