From ac3f07c79794585513a5a1a49f2dd5b489871df6 Mon Sep 17 00:00:00 2001 From: bendn Date: Sat, 30 Sep 2023 06:08:52 +0700 Subject: [PATCH] add Image::circle --- Cargo.toml | 2 +- src/affine.rs | 4 +-- src/drawing/circle.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ src/drawing/mod.rs | 3 +- src/drawing/poly.rs | 13 ++++---- tdata/circle.imgbuf | Bin 0 -> 2500 bytes tdata/circle2.imgbuf | Bin 0 -> 2500 bytes 7 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 src/drawing/circle.rs create mode 100644 tdata/circle.imgbuf create mode 100644 tdata/circle2.imgbuf diff --git a/Cargo.toml b/Cargo.toml index 7bfa3f1..8491fda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fimg" -version = "0.4.10" +version = "0.4.11" authors = ["bend-n "] license = "MIT" edition = "2021" diff --git a/src/affine.rs b/src/affine.rs index 893be81..f4c311e 100644 --- a/src/affine.rs +++ b/src/affine.rs @@ -188,9 +188,7 @@ unsafe fn transpose_non_power_of_two, 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) }; + } + } + } + } +} diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs index 87b4b88..ebc4e99 100644 --- a/src/drawing/mod.rs +++ b/src/drawing/mod.rs @@ -1,5 +1,6 @@ -//! contains drawing operations, like {line, box, triangle, polygon} drawing +//! contains drawing operations, like {line, box, triangle, polygon, circle} drawing mod r#box; +mod circle; mod line; mod poly; mod tri; diff --git a/src/drawing/poly.rs b/src/drawing/poly.rs index e0dd017..3847a56 100644 --- a/src/drawing/poly.rs +++ b/src/drawing/poly.rs @@ -86,6 +86,7 @@ impl, const CHANNELS: usize> Image { } /// Draws a regular convex polygon with a specified number of sides, a radius, and a rotation (radians). + /// Prefer [`Image::circle`] over `poly(.., 600, ..)`. /// Calls into [`Image::tri`] and [`Image::quad`]. /// ``` /// # use fimg::Image; @@ -113,7 +114,7 @@ impl, const CHANNELS: usize> Image { self.tri( add(trans(space + rotation)), add(trans(rotation)), - add(trans(space * 2.0 + rotation)), + add(trans(space.mul_add(2.0, rotation))), c, ); } @@ -122,9 +123,9 @@ impl, const CHANNELS: usize> Image { for i in (0..sides - 1).step_by(2).map(|i| i as f32) { self.quad( r((x, y)), - r(add(trans(space * i + rotation))), - r(add(trans(space * (i + 1.) + rotation))), - r(add(trans(space * (i + 2.) + rotation))), + r(add(trans(space.mul_add(i, rotation)))), + r(add(trans(space.mul_add(i + 1., rotation)))), + r(add(trans(space.mul_add(i + 2., rotation)))), c, ); } @@ -134,8 +135,8 @@ impl, const CHANNELS: usize> Image { // the missing piece self.tri( (x, y), - add(trans(space * i + rotation)), - add(trans(space * (i + 1.) + rotation)), + add(trans(space.mul_add(i, rotation))), + add(trans(space.mul_add(i + 1., rotation))), c, ); } diff --git a/tdata/circle.imgbuf b/tdata/circle.imgbuf new file mode 100644 index 0000000000000000000000000000000000000000..3235779b1ff05fc794beef39f23a95108fe1c099 GIT binary patch literal 2500 zcmeH|OA>=H3`2AOOSj?USd!%yHeGbc23dLvfnkO*o&|5<6$`u%a?&eBy-X2+A4xH| zU}I~Zy*!R=#A8lfVT>ke?0rX@S#ur0q{dqKCQ4om!d>Nd<9k8Rb-Qt;z&H6pLAcc_;z>rGl99&)t zQH*4FWpZOd$)?skOHJ0;v(zSC(D~b5F0*DnVu_29Y$*J{qK@2NCwMHI{)zbp0UmFW literal 0 HcmV?d00001 diff --git a/tdata/circle2.imgbuf b/tdata/circle2.imgbuf new file mode 100644 index 0000000000000000000000000000000000000000..26d22fd7a3429a67725a55511b4325a8c2ac37ee GIT binary patch literal 2500 zcmeIx!4iNV2n106|EDV}8bsKoi-*#S8T$rxN@NXl1Dg)>4m@i5oyil{W{HdWe| n6TFEBw95zxi2x)q03-t`$-z+xJ`