//! draw 2d circles use crate::Image; impl + AsRef<[u8]>, const CHANNELS: usize> Image { /// Draws a circle, using the [Bresenham's circle](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm) algorithm. /// ``` /// # use fimg::Image; /// let mut i = Image::alloc(50, 50); /// i.border_circle((25, 25), 20, [255]); /// # assert_eq!(i.buffer(), include_bytes!("../../tdata/circle.imgbuf")); /// ``` pub fn border_circle(&mut self, (xc, yc): (i32, i32), radius: i32, c: [u8; CHANNELS]) { let mut x = 0; let mut y = radius; let mut p = 1 - radius; /// bounds the pixels macro_rules! bound { ($($x:expr,$y:expr);+;) => { $(if $x >= 0 && $x < self.width() as i32 && $y >= 0 && $y < self.height() as i32 { // SAFETY: ^ unsafe { self.set_pixel($x as u32, $y as u32, &c) }; })+ }; } while x <= y { bound! { xc + x, yc + y; xc + y, yc + x; xc - y, yc + x; xc - x, yc + y; xc - x, yc - y; xc - y, yc - x; xc + y, yc - x; xc + x, yc - y; }; x += 1; if p < 0 { p += 2 * x + 1; } else { y -= 1; p += 2 * (x - y) + 1; } } } /// Draw a filled circle. /// ``` /// # use fimg::Image; /// let mut i = Image::alloc(50, 50); /// i.circle((25, 25), 20, [255]); /// # assert_eq!(i.buffer(), include_bytes!("../../tdata/circle2.imgbuf")); /// ``` pub fn circle(&mut self, (xc, yc): (i32, i32), radius: i32, c: [u8; CHANNELS]) { for x in -radius..radius { let h = ((radius * radius - x * x) as f32).sqrt().round() as i32; for y in -h..h { let x = x + xc; let y = y + yc; if x >= 0 && x < self.width() as i32 && y >= 0 && y < self.height() as i32 { // SAFETY: ^ unsafe { self.set_pixel(x as u32, y as u32, &c) }; } } } } }