From 56b9b96aa69c4671b857cb24c74e020c052c0ffd Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 9 Jan 2020 00:03:05 +0100 Subject: [PATCH] fix edge detection --- fractional/src/easel.rs | 129 ++++++++++++++++++++++++++-------------- fractional/src/main.rs | 8 ++- 2 files changed, 90 insertions(+), 47 deletions(-) diff --git a/fractional/src/easel.rs b/fractional/src/easel.rs index 16973f9..9e6d5a6 100644 --- a/fractional/src/easel.rs +++ b/fractional/src/easel.rs @@ -261,20 +261,22 @@ enum Direction { Left, Right } #[derive(Debug, Clone)] pub struct Polygon(pub Coordinates); +#[derive(Debug, Clone)] +enum VertexIteratorMode { Vertex, Edge } #[derive(Debug, Clone)] pub struct VertexIterator<'a,T> where T: Debug { p :&'a Polygon, top :usize, current :Option, edge :Option>, + mode :VertexIteratorMode, direction :Direction, } impl<'a,T> VertexIterator<'a,T> where T: Add + Sub + Div + Debug + Copy + From { - - fn new(p :&'a Polygon, direction :Direction) -> Self { + fn edge(p :&'a Polygon, direction :Direction) -> Self { let top = p.vert_min(direction); let next = p.next_y(top, direction); let edge = match next { @@ -286,6 +288,19 @@ where T: Add + Sub + Div , top: top , current: next , edge: edge + , mode: VertexIteratorMode::Edge + , direction: direction } + } + + fn vertex(p :&'a Polygon, direction :Direction) -> Self { + let top = p.vert_min(direction); + let next = p.next_y(top, direction); + + VertexIterator { p: p + , top: top + , current: next + , edge: None + , mode: VertexIteratorMode::Vertex , direction: direction } } @@ -314,14 +329,23 @@ where T: Add + Sub + Div type Item = Coordinate; fn next(&mut self) -> Option { - // if for whatever reason edge is "None" finish this iterator. - let next = self.edge.as_mut()?.next(); - - match next { - Some(_) => next, - None => { - self.next_edge()?; - self.next() + match self.mode { + VertexIteratorMode::Edge => { + // if for whatever reason edge is "None" finish this iterator. + let next = self.edge.as_mut()?.next(); + + match next { + Some(_) => next, + None => { + self.next_edge()?; + self.next() + }, + } + }, + VertexIteratorMode::Vertex => { + let current = self.current?; + self.current = self.p.next_y(current, self.direction); + Some(self.p.vertex(current)) }, } } @@ -330,35 +354,56 @@ where T: Add + Sub + Div impl Polygon where T: Add + Sub + Div + Copy + Debug + From { + #[inline] + fn vertex(&self, v :usize) -> Coordinate { + let Polygon(Coordinates(cs)) = self; + cs[v] + } + fn vert_min<'a>(&'a self, d :Direction) -> usize { let Polygon(Coordinates(cs)) = self; type ICoord<'a,T> = (usize, &'a Coordinate); - let fold = | acc :Option>, x :ICoord<'a,T> | + // TODO I guess the problem here is that it does not account for the + // same y vertex on the beggining and the end. So i guess correct + // would be finding the first one and then dependings on the + // given direction either search left or right for same y's. + 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; - match d { - Direction::Left => - if xy < ay {Some(x)} else {Some(a)}, - Direction::Right => - if xy <= ay {Some(x)} else {Some(a)}, - } + if xy < ay {Some(x)} else {Some(a)} }, }; - cs.iter().enumerate().fold(None, fold).unwrap().0 + let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0; + let mut next = self.step(min, d); + + while self.vertex(min).1 == self.vertex(next).1 { + min = next; + next = self.step(min, d); + } + + min + } + + fn left_edge(&self) -> VertexIterator { + VertexIterator::edge(self, Direction::Left) + } + + fn right_edge(&self) -> VertexIterator { + VertexIterator::edge(self, Direction::Right) } fn left_vertices(&self) -> VertexIterator { - VertexIterator::new(self, Direction::Left) + VertexIterator::vertex(self, Direction::Left) } fn right_vertices(&self) -> VertexIterator { - VertexIterator::new(self, Direction::Right) + VertexIterator::vertex(self, Direction::Right) } fn left(&self, v :usize) -> usize { @@ -383,12 +428,6 @@ where T: Add + Sub + Div } } - #[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 @@ -402,28 +441,30 @@ where T: Add + Sub + Div let Coordinate(_, cy, _) = p.vertex(c); let Coordinate(_, ny, _) = p.vertex(n); - match ny.cmp(&cy) { - cmp::Ordering::Less => None, - // TODO On equal we need to find out which one of both to - // keep in the list… (the outermost) - // But how can we find the outermost... - // I think it depends on the previous and next one - // which means this might not be best suited for - // a recursive approach...we could keep both... - // Anyway, it looks like this is only a problem - // for the first vertex so maybe it is enough - // to choose the correct one when starting which - // would be in the vert_min method. - // Well, after adding some logic to vert_min it - // seems it is also relevant for the last one. - cmp::Ordering::Equal => inner(p, c, p.step(n, d), d), - cmp::Ordering::Greater => Some(n), - } + if ny < cy { None } else { Some(n) } } } inner(self, c, self.step(c, d), d) } + + pub fn debug(&self) { + let mut left = self.left_vertices(); + let mut right = self.right_vertices(); + + if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() { + let left :Vec> = self.left_vertices().collect(); + let right :Vec> = self.right_vertices().collect(); + + println!("==="); + println!("== poly : {:?}", self); + println!("== ltop : {:?}", self.vert_min(Direction::Left)); + println!("== rtop : {:?}", self.vert_min(Direction::Right)); + println!("== left : {:?}", left); + println!("== right : {:?}", right); + println!("==="); + } + } } impl Drawable for Polygon @@ -459,7 +500,7 @@ impl Fillable for Polygon where T: Add + Sub + Div + Debug + Clone + Copy + From { fn fill(&self, canvas :&mut dyn Canvas, color :u32) { - let scanlines = self.left_vertices().zip(self.right_vertices()); + let scanlines = self.left_edge().zip(self.right_edge()); for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) { canvas.set_pixel(l, color); diff --git a/fractional/src/main.rs b/fractional/src/main.rs index 92f1652..f0408e2 100644 --- a/fractional/src/main.rs +++ b/fractional/src/main.rs @@ -342,9 +342,10 @@ fn _democanvas( xcb :&XcbEasel let rot1 = TMatrix::combine(vec!(rz, rx, t)); let rot2 = TMatrix::combine(vec!(rz, ry, t)); - let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) ); - //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) - // , ( cube.transform(&rot2), 0x0000FF) ); + let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) + , ( cube.transform(&rot2), 0x0000FF) ); + //let objects = vec!( ( cube.transform(&rot2), 0x0000FF) ); + //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) ); //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) ); >::clear(&mut canvas); @@ -353,6 +354,7 @@ fn _democanvas( xcb :&XcbEasel for (pg, c) in o.project(&camera, &light, color) { //canvas.draw(&pg, Coordinate(0, 0, 0.into()), c); (&pg).fill(&mut canvas, c); + //(&pg).debug(); //println!("\n"); } }