extern crate lyon; //extern crate gnuplot; //use sort_polygons::gnuplot::AxesCommon; //use lyon::tessellation as tess; use lyon::path::iterator::PathIterator; use lyon::path::FlattenedEvent; use lyon::algorithms::path::iterator::Flattened; #[derive(PartialEq)] pub struct Polygon { pub vertices: Vec, } impl Polygon { pub fn new() -> Self { Polygon { vertices: Vec::new(), } } pub fn from_path(path: Flattened) -> Vec { let mut polys = Vec::new(); let mut current_poly = None; for evt in path { match evt { FlattenedEvent::MoveTo(p) => { let mut poly = Polygon::new(); poly.vertices.push(p); current_poly = Some(poly); } FlattenedEvent::LineTo(p) => { if let Some(ref mut poly) = current_poly { poly.vertices.push(p); } } FlattenedEvent::Close => { polys.push(current_poly.unwrap()); current_poly = None; } } } polys } } pub struct PolyPoint<'a> { vertex: &'a lyon::math::Point, prev: &'a lyon::math::Point, next: &'a lyon::math::Point, //pub poly_parent: &'a mut Option<&'a Polygon<'a>>, poly_idx: usize, // TODO: equality operator that just compares 'vertex' } impl<'a> PolyPoint<'a> { pub fn list(polys: &'a Vec) -> Vec { let mut pts = Vec::new(); for (poly_idx, poly) in polys.iter().enumerate() { assert!(poly.vertices.len() >= 3, "Got a degenerate polygon with only {} vertices.", poly.vertices.len()); let mut v1 = &poly.vertices[poly.vertices.len()-2]; // second last element let mut v2 = &poly.vertices[poly.vertices.len()-1]; // last element debug_assert!(v1 != v2, "got same element twice: point {}", v1); for v3 in &poly.vertices { pts.push(PolyPoint { prev: v1, vertex: v2, next: v3, poly_idx: poly_idx, }); //trace!("adding Vertex: {}, {}, {}", v1, v2, v3); v1 = v2; v2 = v3; } } pts } } // returns points sorted in descending y order pub fn sort_poly_points(pts: &mut Vec) { // sorting floats is only possible when we don't have NaNs pts.sort_by(|a, b| b.vertex.y.partial_cmp(&a.vertex.y).unwrap() ); } struct Edge<'a> { upper: &'a lyon::math::Point, // higher y lower: &'a lyon::math::Point, // lower y poly_idx: usize, } impl<'a> Edge<'a> { pub fn interpolate_x(&self, y: f32) -> f32 { debug_assert!(self.upper.y >= y && y >= self.lower.y, "interpolation point must lie between edge's end points: Edge is from {} to {}, query y is {}.", self.upper.y, self.lower.y, y); let r = (y - self.lower.y) / (self.upper.y - self.lower.y); return r * (self.upper.x - self.lower.x) + self.lower.x; } } // insert or remove edge from scanline (scanline is at 'vert') fn handle_edge<'a>(scanline: &mut Vec>, vert: &'a lyon::math::Point, other: &'a lyon::math::Point, poly_idx: usize) { if vert == other { return; // ignore degenerate edges with zero length } //debug_assert!(vert != other, "Edge must consist of two distinct points, but got {} twice.", vert); trace!(" -> handling edge from {} to {} (poly {})", vert, other, poly_idx); if other.y == vert.y { trace!(" -> ignoring horizontal edges"); return; } if other.y > vert.y { // edge ends at scanline // remove it from scanline // TODO: implement ordering trait for Edge that uses interpolated x value so we can find // our edge more efficiently trace!(" -> removing edge, it ends here"); scanline.retain(|edge| edge.lower != vert); } else { // edge starts at scanline // insert it in a sorted fashion let index; match scanline.binary_search_by(|edge| {edge.interpolate_x(vert.y).partial_cmp(&vert.x).unwrap()}) { Ok(i) => index = i, // found other edge at this point. TODO: This should not happen and we probably want at least a warning here. Err(i) => index = i, // not found, but it belongs there } trace!(" -> insert edge at index {}", index); scanline.insert(index, Edge { upper: vert, lower: other, poly_idx: poly_idx }); } } #[derive(Clone)] pub struct ParentInfo<'a> { pub polygon: &'a Polygon, pub parent_idx: Option, pub level: usize, // 0 means poly is outermost } pub fn create_parent_list<'a>(polygons: &'a Vec) -> Vec> { let mut pts = PolyPoint::list(&polygons); sort_poly_points(&mut pts); let mut current_scanline: Vec = Vec::new(); let mut parents: Vec> = vec![None; polygons.len()]; for (_step, pt) in pts.iter().enumerate() { trace!("scanline is at y = {}", pt.vertex.y); // look at edge (prev, vertex) handle_edge(&mut current_scanline, pt.vertex, pt.prev, pt.poly_idx); // look at edge (vertex, next) handle_edge(&mut current_scanline, pt.vertex, pt.next, pt.poly_idx); let mut parent_stack: Vec = Vec::new(); /* let mut fig = gnuplot::Figure::new(); { let mut ax = fig.axes2d(); ax.set_title(&format!("Step {}", _step), &[]); ax.lines(&[pt.vertex.x, pt.prev.x], &[pt.vertex.y, pt.prev.y], &[gnuplot::Color("black"), gnuplot::LineWidth(2.0)]); ax.lines(&[pt.vertex.x, pt.next.x], &[pt.vertex.y, pt.next.y], &[gnuplot::Color("black"), gnuplot::LineWidth(2.0)]); ax.points(&[pt.vertex.x], &[pt.vertex.y], &[gnuplot::Color("black"), gnuplot::PointSize(5.0), gnuplot::PointSymbol('o')]); */ // count number of edges between current vertex and the outside (while ignoring edges of // the current polygon) for ref edge in ¤t_scanline { // only look at edges on the left of the current vertex if edge.interpolate_x(pt.vertex.y) >= pt.vertex.x { break; } // ignore edges from current polygon if edge.poly_idx == pt.poly_idx { continue; } //ax.lines(&[edge.upper.x, edge.lower.x], &[edge.upper.y, edge.lower.y], &[gnuplot::Color("red"), gnuplot::LineWidth(2.0)]); // push or pop polys to/from stack let mut pop = false; if let Some(p) = parent_stack.last() { if *p == edge.poly_idx { pop = true; } } if pop { parent_stack.pop(); } else { parent_stack.push(edge.poly_idx); } } /* } fig.show(); */ trace!(" -> handling point {:?}", pt.vertex); trace!(" -> last edge on stack of {}: {:?}", parent_stack.len(), parent_stack.last()); if !parents[pt.poly_idx].is_some() { // parent information not yet defined, add it parents[pt.poly_idx] = Some(ParentInfo{ polygon: &polygons[pt.poly_idx], parent_idx: parent_stack.last().cloned(), level : parent_stack.len(), }); trace!(" -> assigned parent {:?}", parent_stack.last()); } else if let Some(ref pi) = &parents[pt.poly_idx] { // polygon at poly_idx already has a parent & level defined // make sure it is the right one // (this should not be necessary, just to make sure our implementation is correct // and our assumptions were valid) assert!(pi.level == parent_stack.len(), "Invalid level for polygon {}: Expected {}, but we previously calculated {}.", pt.poly_idx, parent_stack.len(), pi.level); assert!(pi.parent_idx.is_some() == parent_stack.last().is_some(), "Invalid parent for polygon {}: Expected to have parent? {}. Previously determined: {}.", pt.poly_idx, parent_stack.last().is_some(), pi.parent_idx.is_some()); if let Some(p) = pi.parent_idx { assert!(p == *parent_stack.last().unwrap(), "Invalid parent computed: Polygon {} already has parent {}, but we just found {:?} as parent.", pt.poly_idx, p, parent_stack.last()); } } } assert!(parents.len() == polygons.len(), "Did not process all polygons. Only got {} out of {}.", parents.len(), polygons.len()); parents.into_iter().map(|p| p.unwrap()).collect() }