add Image::circle

This commit is contained in:
bendn 2023-09-30 06:08:52 +07:00
parent e405062947
commit ac3f07c797
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
7 changed files with 78 additions and 11 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "fimg" name = "fimg"
version = "0.4.10" version = "0.4.11"
authors = ["bend-n <bend.n@outlook.com>"] authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"

View file

@ -188,9 +188,7 @@ unsafe fn transpose_non_power_of_two<const CHANNELS: usize, T: DerefMut<Target =
for i in 0..size { for i in 0..size {
for j in i..size { for j in i..size {
// SAFETY: caller ensures squarity // SAFETY: caller ensures squarity
unsafe { unsafe { b.swap_unchecked(i * size + j, j * size + i) };
b.swap_unchecked(i * size + j, j * size + i);
};
} }
} }
} }

67
src/drawing/circle.rs Normal file
View file

@ -0,0 +1,67 @@
//! draw 2d circles
use crate::Image;
use std::ops::DerefMut;
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// 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) };
}
}
}
}
}

View file

@ -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 r#box;
mod circle;
mod line; mod line;
mod poly; mod poly;
mod tri; mod tri;

View file

@ -86,6 +86,7 @@ impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
} }
/// Draws a regular convex polygon with a specified number of sides, a radius, and a rotation (radians). /// 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`]. /// Calls into [`Image::tri`] and [`Image::quad`].
/// ``` /// ```
/// # use fimg::Image; /// # use fimg::Image;
@ -113,7 +114,7 @@ impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
self.tri( self.tri(
add(trans(space + rotation)), add(trans(space + rotation)),
add(trans(rotation)), add(trans(rotation)),
add(trans(space * 2.0 + rotation)), add(trans(space.mul_add(2.0, rotation))),
c, c,
); );
} }
@ -122,9 +123,9 @@ impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
for i in (0..sides - 1).step_by(2).map(|i| i as f32) { for i in (0..sides - 1).step_by(2).map(|i| i as f32) {
self.quad( self.quad(
r((x, y)), r((x, y)),
r(add(trans(space * i + rotation))), r(add(trans(space.mul_add(i, rotation)))),
r(add(trans(space * (i + 1.) + rotation))), r(add(trans(space.mul_add(i + 1., rotation)))),
r(add(trans(space * (i + 2.) + rotation))), r(add(trans(space.mul_add(i + 2., rotation)))),
c, c,
); );
} }
@ -134,8 +135,8 @@ impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
// the missing piece // the missing piece
self.tri( self.tri(
(x, y), (x, y),
add(trans(space * i + rotation)), add(trans(space.mul_add(i, rotation))),
add(trans(space * (i + 1.) + rotation)), add(trans(space.mul_add(i + 1., rotation))),
c, c,
); );
} }

BIN
tdata/circle.imgbuf Normal file

Binary file not shown.

BIN
tdata/circle2.imgbuf Normal file

Binary file not shown.