From eed6423cba901170684d08af7a4c60ed58e2919d Mon Sep 17 00:00:00 2001 From: bendn Date: Tue, 26 Sep 2023 12:20:35 +0700 Subject: [PATCH] thick lines --- src/drawing/line.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++- src/drawing/poly.rs | 3 +-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/drawing/line.rs b/src/drawing/line.rs index d6453ca..195d312 100644 --- a/src/drawing/line.rs +++ b/src/drawing/line.rs @@ -131,7 +131,7 @@ impl Iterator for Bresenham { } impl + DerefMut, const CHANNELS: usize> Image { - /// Draw a line from point a to point b + /// Draw a line from point a to point b. /// /// Points not in bounds will not be included. /// @@ -144,6 +144,52 @@ impl + DerefMut, const CHANNELS: usize> I } } } + + /// Draw a thick line from point a to point b. + /// Prefer [`Image::line`] when possible. + /// + /// Points not in bounds will not be included. + /// + /// Uses [`Image::points`]. + /// ``` + /// # use fimg::Image; + /// let mut i = Image::alloc(10, 10); + /// i.thick_line((2.0, 2.0), (8.0, 8.0), 2.0, [255]); + /// # assert_eq!(i.buffer(), b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00"); + /// ``` + pub fn thick_line( + &mut self, + (x1, y1): (f32, f32), + (x2, y2): (f32, f32), + stroke: f32, + color: [u8; CHANNELS], + ) { + let (wx, wy) = { + let (x, y) = (y1 - y2, -(x1 - x2)); + let l = (x * x + y * y).sqrt(); + ((x / l) * (stroke / 2.0), (y / l) * (stroke / 2.0)) + }; + macro_rules! p { + ($x:expr,$y:expr) => { + #[allow(clippy::cast_possible_truncation)] + ($x.round() as i32, $y.round() as i32) + }; + } + // order: + // v x1 v x2 + // [ ] + // ^ x3 ^ x4 + self.points( + &[ + p!(x1 - wx, y1 - wy), // x1 + p!(x2 - wx, y2 - wy), // x2 + p!(x2 + wx, y2 + wy), // x3 + p!(x1 + wx, y1 + wy), // x4 + p!(x1 - wx, y1 - wy), // x1 (close) + ], + color, + ); + } } #[cfg(test)] diff --git a/src/drawing/poly.rs b/src/drawing/poly.rs index 408aa47..aa86168 100644 --- a/src/drawing/poly.rs +++ b/src/drawing/poly.rs @@ -8,6 +8,7 @@ use crate::Image; impl + DerefMut, const CHANNELS: usize> Image { /// Draws a filled polygon from a slice of points. Please close your poly. (first == last) + /// /// Borrowed from [imageproc](https://docs.rs/imageproc/latest/src/imageproc/drawing/polygon.rs.html#31), modified for less allocations. /// ``` /// # use fimg::Image; @@ -48,8 +49,6 @@ impl + DerefMut, const CHANNELS: usize> I } } intersections.sort_unstable(); - // SAFETY: must. - unsafe { crate::assert_unchecked!(intersections.len() % 2 == 0) }; for &[x, y_] in intersections.array_chunks::<2>() { let mut from = min(x, self.width() as i32); let mut to = min(y_, self.width() as i32 - 1);