Browse Source

fix edge detection

master
Georg Hopp 6 years ago
parent
commit
56b9b96aa6
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 129
      fractional/src/easel.rs
  2. 8
      fractional/src/main.rs

129
fractional/src/easel.rs

@ -261,20 +261,22 @@ enum Direction { Left, Right }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Polygon<T>(pub Coordinates<T>); pub struct Polygon<T>(pub Coordinates<T>);
#[derive(Debug, Clone)]
enum VertexIteratorMode { Vertex, Edge }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VertexIterator<'a,T> where T: Debug { pub struct VertexIterator<'a,T> where T: Debug {
p :&'a Polygon<T>, p :&'a Polygon<T>,
top :usize, top :usize,
current :Option<usize>, current :Option<usize>,
edge :Option<LineIterator<T>>, edge :Option<LineIterator<T>>,
mode :VertexIteratorMode,
direction :Direction, direction :Direction,
} }
impl<'a,T> VertexIterator<'a,T> impl<'a,T> VertexIterator<'a,T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
+ Debug + Copy + From<i32> { + Debug + Copy + From<i32> {
fn new(p :&'a Polygon<T>, direction :Direction) -> Self {
fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
let top = p.vert_min(direction); let top = p.vert_min(direction);
let next = p.next_y(top, direction); let next = p.next_y(top, direction);
let edge = match next { let edge = match next {
@ -286,6 +288,19 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
, top: top , top: top
, current: next , current: next
, edge: edge , edge: edge
, mode: VertexIteratorMode::Edge
, direction: direction }
}
fn vertex(p :&'a Polygon<T>, 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 } , direction: direction }
} }
@ -314,14 +329,23 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
type Item = Coordinate<T>; type Item = Coordinate<T>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// 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<Output = T> + Sub<Output = T> + Div<Output = T>
impl<T> Polygon<T> impl<T> Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
+ Copy + Debug + From<i32> { + Copy + Debug + From<i32> {
#[inline]
fn vertex(&self, v :usize) -> Coordinate<T> {
let Polygon(Coordinates(cs)) = self;
cs[v]
}
fn vert_min<'a>(&'a self, d :Direction) -> usize { fn vert_min<'a>(&'a self, d :Direction) -> usize {
let Polygon(Coordinates(cs)) = self; let Polygon(Coordinates(cs)) = self;
type ICoord<'a,T> = (usize, &'a Coordinate<T>); type ICoord<'a,T> = (usize, &'a Coordinate<T>);
let fold = | acc :Option<ICoord<'a,T>>, 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<ICoord<'a,T>>, x :ICoord<'a,T>|
match acc { match acc {
None => Some(x), None => Some(x),
Some(a) => { Some(a) => {
let Coordinate(_, ay, _) = a.1; let Coordinate(_, ay, _) = a.1;
let Coordinate(_, xy, _) = x.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<T> {
VertexIterator::edge(self, Direction::Left)
}
fn right_edge(&self) -> VertexIterator<T> {
VertexIterator::edge(self, Direction::Right)
} }
fn left_vertices(&self) -> VertexIterator<T> { fn left_vertices(&self) -> VertexIterator<T> {
VertexIterator::new(self, Direction::Left)
VertexIterator::vertex(self, Direction::Left)
} }
fn right_vertices(&self) -> VertexIterator<T> { fn right_vertices(&self) -> VertexIterator<T> {
VertexIterator::new(self, Direction::Right)
VertexIterator::vertex(self, Direction::Right)
} }
fn left(&self, v :usize) -> usize { fn left(&self, v :usize) -> usize {
@ -383,12 +428,6 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
} }
} }
#[inline]
fn vertex(&self, v :usize) -> Coordinate<T> {
let Polygon(Coordinates(cs)) = self;
cs[v]
}
fn next_y(&self, c :usize, d :Direction) -> Option<usize> { fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
fn inner<T>( p :&Polygon<T> fn inner<T>( p :&Polygon<T>
, c :usize , c :usize
@ -402,28 +441,30 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
let Coordinate(_, cy, _) = p.vertex(c); let Coordinate(_, cy, _) = p.vertex(c);
let Coordinate(_, ny, _) = p.vertex(n); 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) 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<Coordinate<T>> = self.left_vertices().collect();
let right :Vec<Coordinate<T>> = 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<T> Drawable<T> for Polygon<T> impl<T> Drawable<T> for Polygon<T>
@ -459,7 +500,7 @@ impl<T> Fillable<T> for Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
+ Debug + Clone + Copy + From<i32> { + Debug + Clone + Copy + From<i32> {
fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) { fn fill(&self, canvas :&mut dyn Canvas<T>, 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)) { for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {
canvas.set_pixel(l, color); canvas.set_pixel(l, color);

8
fractional/src/main.rs

@ -342,9 +342,10 @@ fn _democanvas<T>( xcb :&XcbEasel
let rot1 = TMatrix::combine(vec!(rz, rx, t)); let rot1 = TMatrix::combine(vec!(rz, rx, t));
let rot2 = TMatrix::combine(vec!(rz, ry, 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) ); //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );
<XcbCanvas as Canvas<T>>::clear(&mut canvas); <XcbCanvas as Canvas<T>>::clear(&mut canvas);
@ -353,6 +354,7 @@ fn _democanvas<T>( xcb :&XcbEasel
for (pg, c) in o.project(&camera, &light, color) { for (pg, c) in o.project(&camera, &light, color) {
//canvas.draw(&pg, Coordinate(0, 0, 0.into()), c); //canvas.draw(&pg, Coordinate(0, 0, 0.into()), c);
(&pg).fill(&mut canvas, c); (&pg).fill(&mut canvas, c);
//(&pg).debug();
//println!("\n"); //println!("\n");
} }
} }

Loading…
Cancel
Save