use std::collections::VecDeque; use Polygon::{PolyQuad, PolyTri}; use {Polygon, Quad, Triangle}; /// provides a way to convert a polygon down to triangles pub trait EmitTriangles { /// The content of each point in the face type Vertex; /// convert a polygon to one or more triangles, each triangle /// is returned by calling `emit` fn emit_triangles(&self, F) where F: FnMut(Triangle); } impl EmitTriangles for Quad { type Vertex = T; fn emit_triangles(&self, mut emit: F) where F: FnMut(Triangle), { let &Quad { ref x, ref y, ref z, ref w, } = self; emit(Triangle::new(x.clone(), y.clone(), z.clone())); emit(Triangle::new(z.clone(), w.clone(), x.clone())); } } impl EmitTriangles for Triangle { type Vertex = T; fn emit_triangles(&self, mut emit: F) where F: FnMut(Triangle), { emit(self.clone()); } } impl EmitTriangles for Polygon { type Vertex = T; fn emit_triangles(&self, emit: F) where F: FnMut(Triangle), { match self { &PolyTri(ref t) => t.emit_triangles(emit), &PolyQuad(ref q) => q.emit_triangles(emit), } } } /// `Triangluate` is a easy to to convert any Polygon stream to /// a stream of triangles. This is useful since Quads and other geometry /// are not supported by modern graphics pipelines like OpenGL. pub trait Triangulate { /// convert a stream of Polygons to a stream of triangles fn triangulate(self) -> TriangulateIterator; } impl, T: Iterator> Triangulate for T { fn triangulate(self) -> TriangulateIterator { TriangulateIterator::new(self) } } /// Used to iterator of polygons into a iterator of triangles pub struct TriangulateIterator { source: SRC, buffer: VecDeque>, } impl, SRC: Iterator> TriangulateIterator { fn new(src: SRC) -> TriangulateIterator { TriangulateIterator { source: src, buffer: VecDeque::new(), } } } impl, SRC: Iterator> Iterator for TriangulateIterator { type Item = Triangle; fn size_hint(&self) -> (usize, Option) { let (n, _) = self.source.size_hint(); (n, None) } fn next(&mut self) -> Option { loop { match self.buffer.pop_front() { Some(v) => return Some(v), None => (), } match self.source.next() { Some(p) => p.emit_triangles(|v| self.buffer.push_back(v)), None => return None, } } } }