Browse Source

Add Drawable primitives

master
Georg Hopp 6 years ago
parent
commit
b36e20a2a0
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 235
      fractional/src/easel.rs
  2. 1
      fractional/src/lib.rs
  3. 72
      fractional/src/main.rs

235
fractional/src/easel.rs

@ -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)
}
}

1
fractional/src/lib.rs

@ -23,6 +23,7 @@ extern crate lazy_static;
pub type Error = &'static str;
pub mod continuous;
pub mod easel;
pub mod fractional;
pub mod transform;
pub mod trigonometry;

72
fractional/src/main.rs

@ -18,7 +18,6 @@
// 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::convert::{TryFrom, TryInto, Into};
use std::f64::consts::PI as FPI;
use std::fmt::Display;
@ -26,47 +25,13 @@ use std::num::TryFromIntError;
use std::ops::{Add,Sub,Neg,Mul,Div};
use fractional::continuous::Continuous;
use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
, Polygon, Rectangle};
use fractional::fractional::{Fractional, from_vector};
use fractional::trigonometry::Trig;
use fractional::vector::{Vector};
use fractional::transform::{TMatrix, translate, rotate_x, rotate_y, rotate_z, rotate_v};
// Tail recursive Bresenham line with integer incremental error.
fn line(a :(u32, u32), b :(u32, u32)) -> Vec<(u32, u32)>{
fn inner( v :&mut [(u32, u32)]
, bx :u32, by :u32
, dx :i32, dy :i32
, sx :i32, sy :i32
, err :i32) {
let (x, y) = v[0];
if x != bx || y != by {
let (x, y, err) = match (2*err as i32 >= dy, 2*err as i32 <= dx) {
(true, false) => ((x as i32 + sx) as u32, y, err + dy),
(false, true) => (x, (y as i32 + sy) as u32, err + dx),
_ => ( (x as i32 + sx) as u32
, (y as i32 + sy) as u32
, err + dx + dy ),
};
v[1] = (x, y);
inner(&mut v[1..], bx, by, dx, dy, sx, sy, err);
}
}
let (ax, ay) = a;
let (bx, by) = b;
let dx = (bx as i32 - ax as i32).abs();
let sx :i32 = if ax < bx { 1 } else { -1 };
let dy = -(by as i32 - ay as i32).abs();
let sy :i32 = if ay < by { 1 } else { -1 };
let mut v :Vec<(u32, u32)> = vec!((0, 0); cmp::max(dx, -dy) as usize + 1);
v[0] = (ax, ay);
inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy);
v
}
fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
let r = v.iter().fold(0, |acc, x| acc + x);
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>)
}
fn _line() {
println!("{:>14} : {:?}", "Line", line((0,1), (6,4)));
println!("{:>14} : {:?}", "Line", line((0,4), (6,1)));
println!("{:>14} : {:?}", "Line", line((6,1), (0,4)));
println!("{:>14} : {:?}", "Line", line((6,4), (0,1)));
println!("{:>14} : {:?}", "Line", line((0,1), (6,8)));
println!("{:>14} : {:?}", "Line", line((0,8), (6,1)));
println!("{:>14} : {:?}", "Line", line((6,1), (0,8)));
println!("{:>14} : {:?}", "Line", line((6,8), (0,1)));
let a = (Coordinate(0, 1), Coordinate(6, 4));
let b = (Coordinate(0, 4), Coordinate(6, 1));
let c = (Coordinate(1, 0), Coordinate(6, 8));
let d = (Coordinate(1, 8), Coordinate(6, 0));
for i in [a, b, c, d].iter() {
println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot());
println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot());
}
println!();
let r = Rectangle(Coordinate(1, 1), Coordinate(10, 5));
println!("{:>14} : {}", r, r.plot());
println!();
let pl = Polyline(
Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1)));
println!("{:>14} : {}", pl, pl.plot());
println!();
let pg = Polygon(
Coordinates(vec!( Coordinate( 0, -20)
, Coordinate( 20, 20)
, Coordinate(-20, 20) )));
println!("{:>14} : {}", pg, pg.plot());
}
fn main() {

Loading…
Cancel
Save