From 29c366d709d8e31ae0f16d9f2a18b9e7aeab6147 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Tue, 7 Jan 2020 21:24:12 +0100 Subject: [PATCH] More iterators --- fractional/src/easel.rs | 356 +++++++++++++++++++++------------------- 1 file changed, 190 insertions(+), 166 deletions(-) diff --git a/fractional/src/easel.rs b/fractional/src/easel.rs index f72a27e..85a8e34 100644 --- a/fractional/src/easel.rs +++ b/fractional/src/easel.rs @@ -62,8 +62,7 @@ pub struct LineIterator where T: Debug { , b :Coordinate , dx :i32 , dy :i32 - , dzx :T - , dzy :T + , dz :T , sx :i32 , sy :i32 , err :i32 @@ -75,41 +74,43 @@ where T: Add + Debug + Copy + From { type Item = Coordinate; fn next(&mut self) -> Option { - let Coordinate(ax, ay, az) = match self.a { - None => self.b, - Some(a) => a, - }; - let Coordinate(bx, by, _) = self.b; - - //println!("== {:?}", self); - - if ax != bx || ay != by { - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) { - (true, false) => { - let r = self.a; - self.a = Some(Coordinate(ax+self.sx, ay, az+self.dzx)); - self.err = self.err + self.dy; - if self.only_edges { self.next() } else { r } - }, - (false, true) => { - let r = self.a; - self.a = Some(Coordinate(ax, ay+self.sy, az+self.dzy)); - self.err = self.err + self.dx; - r - }, - _ => { - let r = self.a; - self.a = Some(Coordinate( ax + self.sx - , ay + self.sy - , az + self.dzy )); - self.err = self.err + self.dx + self.dy; - r - }, - } - } else { - match self.a { - None => None, - Some(a) => { self.a = None; Some(a) } + match self.a { + None => None, + Some(a) => { + let Coordinate(ax, ay, az) = a; + let Coordinate(bx, by, _) = self.b; + + if ax != bx || ay != by { + match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) { + (true, false) => { + let r = self.a; + self.a = Some(Coordinate( ax + self.sx + , ay + , az + self.dz )); + self.err = self.err + self.dy; + if self.only_edges { self.next() } else { r } + }, + (false, true) => { + let r = self.a; + self.a = Some(Coordinate( ax + , ay + self.sy + , az + self.dz )); + self.err = self.err + self.dx; + r + }, + _ => { + let r = self.a; + self.a = Some(Coordinate( ax + self.sx + , ay + self.sy + , az + self.dz )); + self.err = self.err + self.dx + self.dy; + r + }, + } + } else { + self.a = None; + Some(self.b) + } } } } @@ -122,17 +123,14 @@ where T: Add + Sub + Div let Coordinate(ax, ay, az) = self; let Coordinate(bx, by, bz) = *b; - let dx = (bx - ax).abs(); - let dy = -(by - ay).abs(); - let size = cmp::min(dx, -dy); - let dz = (bz - az) / size.into(); + let dx = (bx - ax).abs(); + let dy = -(by - ay).abs(); LineIterator { a: Some(self) , b: *b , dx: dx , dy: dy - , dzx: if size == dx { dz } else { 0.into() } - , dzy: if size == -dy { dz } else { 0.into() } + , dz: (bz - az) / cmp::max(dx, -dy).into() , sx: if ax < bx { 1 } else { -1 } , sy: if ay < by { 1 } else { -1 } , err: dx + dy @@ -140,52 +138,20 @@ where T: Add + Sub + Div } } - // Tail recursive Bresenham line with integer incremental error. + fn line_iter(self, b :&Self) -> LineIterator { + self.iter(b, false) + } + fn line(self, b :&Self) -> Vec { - self.iter(b, false).collect() + self.line_iter(b).collect() } - /* - * Special line algorithm just putting the outermost x values per - * line into the resulting Vector. - * This expects y of b larger than y of self. - */ - fn edge(self, b :&Self) -> Vec { - println!("== New edge: {:?} - {:?}", self, b); - self.iter(b, true).collect() - /* - let Coordinate(mut x, mut y, mut z) = self; - let Coordinate( bx, by, bz) = *b; - - // next should be called with the negative of this… but dz depends - // on the positive this. - let dy = -(by - y).abs(); - let dx = (bx - x).abs(); - let sx = if x < bx { 1 } else { -1 }; - let dz = (bz - z) / (-dy).into(); - let mut err = dx + dy; - - let mut v = Vec::>::with_capacity((-dy) as usize); - - while y != by { - match (2*err >= dy, 2*err <= dx) { - (true, false) => { x = x + sx - ; err = err + dy }, - (false, true) => { v.push(Coordinate(x, y, z)) - ; y = y + 1 - ; z = z + dz - ; err = err + dx }, - _ => { v.push(Coordinate(x, y, z)) - ; x = x + sx - ; y = y + 1 - ; z = z + dz - ; err = err + dx + dy }, - } - } + fn edge_iter(self, b :&Self) -> LineIterator { + self.iter(b, true) + } - v.push(*b); - v - */ + fn edge(self, b :&Self) -> Vec { + self.edge_iter(b).collect() } } @@ -252,40 +218,6 @@ impl Display for Line { } } -// In 3D a rectangle is not as trivial as in 2D, it might be somehow rotate -// and thus we need to specify a Z offset for the other two corners. -// As I do not need rectangle at all I just comment out this code for now. -/* -#[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, az) = a; - let Coordinate(cx, cy, cz) = 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); @@ -320,9 +252,126 @@ impl Display for Polyline where T: Copy { } } +#[derive(Debug, Clone, Copy)] +enum Direction { Left, Right } + #[derive(Debug, Clone)] pub struct Polygon(pub Coordinates); +#[derive(Debug, Clone)] +pub struct VertexIterator<'a,T> where T: Debug { + p :&'a Polygon, + top :usize, + current :Option, + inner :Option>, + direction :Direction, +} + +impl<'a,T> Iterator for VertexIterator<'a,T> +where T: Add + Sub + Div + + Debug + Copy + From { + type Item = Coordinate; + + fn next(&mut self) -> Option { + let inner = match self.inner { + Some(i) => i, + None => { + let current = self.current?; + let next = self.p.next_y(current, self.direction)?; + self.p.vertex(current).edge_iter(&self.p.vertex(next)) + }, + } + + match self.current { + None => None, + Some(c) => { + let r = self.p.vertex(c); + self.current = self.p.next_y(c, self.direction); + Some(r) + }, + } + } +} + +impl Polygon where T: Copy + Debug { + fn vert_min<'a>(&'a self) -> usize { + let Polygon(Coordinates(cs)) = self; + + type ICoord<'a,T> = (usize, &'a Coordinate); + + let fold = | acc :Option>, x :ICoord<'a,T> | + match acc { + None => Some(x), + Some(a) => { + let Coordinate(_, ay, _) = a.1; + let Coordinate(_, xy, _) = x.1; + if xy < ay {Some(x)} else {Some(a)} + }, + }; + + cs.iter().enumerate().fold(None, fold).unwrap().0 + } + + fn left_vertices(&self) -> VertexIterator { + VertexIterator { p: &self + , top: self.vert_min() + , current: Some(self.vert_min()) + , inner: None + , direction: Direction::Left } + } + + fn left(&self, v :usize) -> usize { + let Polygon(Coordinates(cs)) = self; + + match v { + 0 => cs.len() - 1, + _ => v - 1, + } + } + + fn right(&self, v :usize) -> usize { + let Polygon(Coordinates(cs)) = self; + + (v + 1) % cs.len() + } + + fn step(&self, v :usize, d :Direction) -> usize { + match d { + Direction::Left => self.left(v), + Direction::Right => self.right(v), + } + } + + #[inline] + fn vertex(&self, v :usize) -> Coordinate { + let Polygon(Coordinates(cs)) = self; + cs[v] + } + + fn next_y(&self, c :usize, d :Direction) -> Option { + fn inner( p :&Polygon + , c :usize + , n :usize + , d :Direction) -> Option + where T: Copy + Debug { + if c == n { + None + } else { + let Coordinate(_, cy, _) = p.vertex(c); + let Coordinate(_, ny, _) = p.vertex(n); + + match ny.cmp(&cy) { + cmp::Ordering::Less => None, + cmp::Ordering::Equal => inner(p, c, p.step(n, d), d), + cmp::Ordering::Greater => Some(n), + } + } + } + + inner(self, c, self.step(c, d), d) + } +} + impl Drawable for Polygon where T: Add + Sub + Div + Debug + Clone + Copy + From { @@ -356,70 +405,45 @@ impl Fillable for Polygon where T: Add + Sub + Div + Debug + Clone + Copy + From { fn fill(&self) -> Coordinates { - - fn next_y( cs :&[Coordinate] - , c :usize - , f :&dyn Fn(usize) -> usize) -> Option { - fn inner( cs :&[Coordinate] - , c :usize - , n :usize - , f :&dyn Fn(usize) -> usize) -> Option { - if c == n { - None - } else { - let Coordinate(_, cy, _) = cs[c]; - let Coordinate(_, ny, _) = cs[n]; - - match ny.cmp(&cy) { - cmp::Ordering::Less => None, - cmp::Ordering::Equal => inner(cs, c, f(n), f), - cmp::Ordering::Greater => Some(n), - } - } - } - - inner(cs, c, f(c), f) - } - let Polygon(Coordinates(cs)) = self; - let vert_min = cs.iter().enumerate() - . fold( None - , |acc, x| match acc { - None => Some(x), - Some(a) => { - let Coordinate(_, ay, _) = a.1; - let Coordinate(_, xy, _) = x.1; - if xy < ay {Some(x)} else {Some(a)} } } ) - . unwrap().0; - - println!("== vert_min: [{:?}] - {:?}", vert_min, cs[vert_min]); + let vert_min = self.vert_min(); - let right = |x :usize| (x + 1) % cs.len(); - let left = |x :usize| if x == 0 { cs.len() - 1 } else { x - 1 }; + println!("== vert_min: [{}] {:?}", vert_min, cs[vert_min]); - let mut r = (vert_min, next_y(cs, vert_min, &right)); - let mut l = (vert_min, next_y(cs, vert_min, &left)); + let mut r = (vert_min, self.next_y(vert_min, Direction::Right)); + let mut l = (vert_min, self.next_y(vert_min, Direction::Left)); let mut l_edge :Vec> = Vec::new(); let mut r_edge :Vec> = Vec::new(); let append_edge = | v :&mut Vec> - , e :&(usize, Option) | { - match *e { - (_, None) => *e, + , e :(usize, Option) + , f :Direction | { + match e { + (_, None) => e, (a, Some(b)) => { - println!("== l: [{:?}] - {:?}", e, cs[b]); let mut edge = cs[a].edge(&cs[b]); v.append(&mut edge); - (b, next_y(cs, b, &left)) + (b, self.next_y(b, f)) }, } }; + let print_current = |s :&str, e :(usize, Option)| { + match e.1 { + None => println!( "== {}: [{:?}] - {:?}" + , s, e.1, "None"), + Some(e) => println!( "== {}: [{:?}] - {:?}" + , s, e, cs[e]), + } + }; + while l.1 != None || r.1 != None { - l = append_edge(&mut l_edge, &l); - r = append_edge(&mut r_edge, &r); + print_current("l", l); + l = append_edge(&mut l_edge, l, Direction::Left); + print_current("r", r); + r = append_edge(&mut r_edge, r, Direction::Right); } println!("== [{}] {:?}", l_edge.len(), l_edge);