From d550a7e71ec9aee3f44b47b1867b322ac8edbd12 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 29 Oct 2026 10:39:25 +0000 Subject: [PATCH] Move Bresenham line drawing into library from Hough example --- examples/hough.rs | 130 +++++++++++++--------------------------------- src/draw.rs | 43 +++++++++++++++ src/lib.rs | 1 + 3 files changed, 81 insertions(+), 93 deletions(-) create mode 100644 src/draw.rs diff --git a/examples/hough.rs b/examples/hough.rs index 7be8ad0..8a4e7ec 100644 --- a/examples/hough.rs +++ b/examples/hough.rs @@ -1,10 +1,8 @@ mod common; -use ccvl::filter::*; -use ccvl::hough; -use ccvl::image::*; +use ccvl::*; -const LINE: SRGBA = SRGBA { +const LINE: image::SRGBA = image::SRGBA { r: 1.0, g: 0.0, b: 0.0, @@ -13,102 +11,48 @@ const LINE: SRGBA = SRGBA { fn main() -> std::process::ExitCode { common::process_image(|mut img| { - let greyscale = img.map(|p| Luminance::from(p)); - let edges = canny(greyscale); + let greyscale = img.map(|p| image::Luminance::from(p)); + let edges = filter::canny(greyscale); for line in hough::lines(10.0, edges) { - draw(line, &mut img); + let ((x0, y0), (x1, y1)) = endpoints(line, img.extent); + draw::line(x0, y0, x1, y1, &mut img, LINE); } img }) } -fn in_bounds(q: &(f32, f32), lim: Extent) -> bool { +fn endpoints( + l: hough::Line, + lim: image::Extent, +) -> ((usize, usize), (usize, usize)) { + if l.theta.abs() < 1e-3 { + ((l.rho as usize, 0), (l.rho as usize, lim.y - 1)) + } else if l.theta - std::f32::consts::PI / 2.0 < 1e-3 { + ((0, l.rho as usize), (lim.x - 1, l.rho as usize)) + } else { + let w = lim.x as f32 - 1e-3; + let h = lim.y as f32 - 1e-3; + + let ros = l.rho / l.theta.sin(); + let roc = l.rho / l.theta.cos(); + let t = l.theta.tan(); + + let candidates: [(f32, f32); 4] = + [(roc - h * t, h), (0.0, ros), (roc, 0.0), (w, ros - w / t)]; + let res = candidates + .into_iter() + .filter(|p| in_bounds(p, lim)) + .map(|(x, y)| (x as usize, y as usize)) + .collect::>(); + if res.len() != 2 { + panic!("Unexpected number of endpoints for {:?}", l); + } + (res[0], res[1]) + } +} + +fn in_bounds(q: &(f32, f32), lim: image::Extent) -> bool { let x_in = 0.0 <= q.0 && q.0 < lim.x as f32; let y_in = 0.0 <= q.1 && q.1 < lim.y as f32; x_in && y_in } - -fn endpoints( - l: hough::Line, - lim: Extent, -) -> ((usize, usize), (usize, usize)) { - let w = lim.x as f32 - 1e-3; - let h = lim.y as f32 - 1e-3; - - let ros = l.rho / l.theta.sin(); - let roc = l.rho / l.theta.cos(); - let t = l.theta.tan(); - - let candidates: [(f32, f32); 4] = - [(roc - h * t, h), (0.0, ros), (roc, 0.0), (w, ros - w / t)]; - let res = candidates - .into_iter() - .filter(|p| in_bounds(p, lim)) - .map(|(x, y)| (x as usize, y as usize)) - .collect::>(); - if res.len() != 2 { - panic!("Unexpected number of endpoints for {:?}", l); - } - (res[0], res[1]) -} - -fn draw(l: hough::Line, img: &mut Image) { - if l.theta.abs() < 1e-3 { - // vertical line - let x = l.rho as usize; - for y in 0..img.extent.y { - if x >= img.extent.x || y >= img.extent.y { - return; - } - *img.at_mut(x, y) = LINE; - } - } else if (l.theta - std::f32::consts::PI / 2.0) < 1e-3 { - // horizontal line - let y = l.rho as usize; - for x in 0..img.extent.x { - if x >= img.extent.x || y >= img.extent.y { - return; - } - *img.at_mut(x, y) = LINE; - } - } else { - bresenham(endpoints(l, img.extent), img); - } -} - -fn bresenham(qs: ((usize, usize), (usize, usize)), img: &mut Image) { - let ((x0, y0), (x1, y1)) = qs; - - let dx = x0.abs_diff(x1) as isize; - let dy = -(y0.abs_diff(y1) as isize); - - let sx = if x0 < x1 { 1 } else { -1 }; - let sy = if y0 < y1 { 1 } else { -1 }; - - let mut x = x0; - let mut y = y0; - let mut error = dx + dy; - - loop { - if x >= img.extent.x || y >= img.extent.y { - return; - } - - *img.at_mut(x, y) = LINE; - let e2 = 2 * error; - if e2 >= dy { - if x == x1 { - break; - } - error += dy; - x = (x as isize + sx) as usize; - } - if e2 <= dx { - if y == y1 { - break; - } - error += dx; - y = (y as isize + sy) as usize; - } - } -} diff --git a/src/draw.rs b/src/draw.rs new file mode 100644 index 0000000..d82b4df --- /dev/null +++ b/src/draw.rs @@ -0,0 +1,43 @@ +use crate::*; + +pub fn line( + x0: usize, + y0: usize, + x1: usize, + y1: usize, + img: &mut image::Image

, + colour: P, +) { + let dx = x0.abs_diff(x1) as isize; + let dy = -(y0.abs_diff(y1) as isize); + + let sx = if x0 < x1 { 1 } else { -1 }; + let sy = if y0 < y1 { 1 } else { -1 }; + + let mut x = x0; + let mut y = y0; + let mut error = dx + dy; + + loop { + if x >= img.extent.x || y >= img.extent.y { + return; + } + + *img.at_mut(x, y) = colour; + let e2 = 2 * error; + if e2 >= dy { + if x == x1 { + break; + } + error += dy; + x = (x as isize + sx) as usize; + } + if e2 <= dx { + if y == y1 { + break; + } + error += dx; + y = (y as isize + sy) as usize; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index d538bd8..6e07453 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod contour; +pub mod draw; pub mod filter; pub mod hough; pub mod image;