diff --git a/examples/contours.rs b/examples/contours.rs index abbdae5..c97777b 100644 --- a/examples/contours.rs +++ b/examples/contours.rs @@ -21,12 +21,15 @@ fn main() -> std::process::ExitCode { let thresholded = filter::threshold_auto(greyscale); let contours = contour::find(thresholded); for contour in contours { - for (x, y) in contour.trace { - *img.at_mut(x, y) = match contour.kind { - contour::Kind::Inner => INNER, - contour::Kind::Outer => OUTER, - }; - } + let n = contour.vertices.len(); + for i in 0..n { + let (x0, y0) = contour.vertices[i]; + let (x1, y1) = contour.vertices[(i + 1) % n]; + draw::line(x0, y0, x1, y1, &mut img, match contour.kind { + contour::Kind::Outer => OUTER, + contour::Kind::Inner => INNER, + }); + } } img }) diff --git a/src/contour.rs b/src/contour.rs index 3f59110..3895f1a 100644 --- a/src/contour.rs +++ b/src/contour.rs @@ -8,7 +8,7 @@ pub enum Kind { #[derive(Debug, PartialEq)] pub struct Contour { - pub trace: Vec<(usize, usize)>, + pub vertices: Vec<(usize, usize)>, pub children: Vec, pub parent: Option, pub kind: Kind, @@ -58,66 +58,73 @@ pub fn find(img: image::Image) -> Vec { let mut parent = None; for x in 0..map.extent.x { let q = (x, y); - if foreground(&map, q) { - let prev_bg = background(&map, q.prev_x()); - let next_bg = background(&map, q.next_x()); - if prev_bg || next_bg { - let (dir, kind) = if prev_bg { - (Dir::W, Kind::Outer) - } else { - (Dir::E, Kind::Inner) - }; - let label = contours.len(); - let trace = trace(&mut map, q, dir, label); - contours.push(Contour::new(parent, kind, trace)); - if let Some(index) = parent { - contours[index].add_child(label); - } - } + if foreground(&map, q) && background(&map, q.prev_x()) { + add(q, Kind::Outer, parent, &mut contours, &mut map); + } else if foreground(&map, q) && background(&map, q.next_x()) { + add(q, Kind::Inner, parent, &mut contours, &mut map); } else if let Some(label) = traced(&map, q) { - if background(&map, q.prev_x()) { - parent = Some(label); - } else if background(&map, q.next_x()) { - parent = contours[label].parent; - } - } + if background(&map, q.prev_x()) { + parent = Some(label); + } else if background(&map, q.next_x()) { + parent = contours[label].parent; + } + } } } contours } +fn add( + start: (usize, usize), + kind: Kind, + parent: Option, + contours: &mut Vec, + map: &mut image::Image, +) { + let label = contours.len(); + let vertices = trace(map, start, kind.start_dir(), label); + contours.push(Contour::new(parent, kind, vertices)); + if let Some(index) = parent { + contours[index].add_child(label); + } +} + fn trace( img: &mut image::Image, start_q: (usize, usize), - mut dir: Dir, + start_dir: Dir, label: usize, ) -> Vec<(usize, usize)> { let mut q = start_q; - dir = dir.next(); + let mut dir = start_dir; + while background(img, dir.from(q)) { + dir.next(); + } - let mut path = Vec::new(); - 'outer: loop { - if !q.in_bounds(img.extent) { - break; - } + let mut vertices = Vec::new(); + loop { q.set(img, Pixel::Traced(label)); - path.push(q); - let start = dir; - while background(img, dir.from(q)) { - dir = dir.next(); - if dir == start { - break 'outer; - } - } - q = dir.from(q); + let prev_dir = dir; dir = dir.flip().next(); + q = loop { + let qp = dir.from(q); + if !background(img, qp) { + if dir != prev_dir { + vertices.push(q) + } + break qp; + } + dir = dir.next(); + }; - if q == start_q { - break; + if q == start_q || !q.in_bounds(img.extent) { + if dir != start_dir { + vertices.push(q); + } + break vertices; } } - path } fn foreground(img: &image::Image, q: (usize, usize)) -> bool { @@ -141,6 +148,15 @@ fn traced(img: &image::Image, q: (usize, usize)) -> Option { } } +impl Kind { + fn start_dir(self) -> Dir { + match self { + Kind::Outer => Dir::E, + Kind::Inner => Dir::W, + } + } +} + impl Dir { fn next(self) -> Self { match self { @@ -222,19 +238,19 @@ impl Contour { fn new( parent: Option, kind: Kind, - trace: Vec<(usize, usize)>, + vertices: Vec<(usize, usize)>, ) -> Self { Self { - trace, + vertices, children: Vec::new(), parent, kind, } } - fn add_child(&mut self, child: usize) { - self.children.push(child); - } + fn add_child(&mut self, child: usize) { + self.children.push(child); + } } impl Default for Pixel {