From 3a2fef94230f35d948634ffef83660afdffa0bad Mon Sep 17 00:00:00 2001 From: Arjun Satarkar Date: Thu, 1 Jun 2023 19:01:24 +0530 Subject: Complete libhitomezashi, reset project --- libhitomezashi/src/lib.rs | 63 ++++++++++++++++++++++++++ libhitomezashi/src/pixel_buffer.rs | 93 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 libhitomezashi/src/lib.rs create mode 100644 libhitomezashi/src/pixel_buffer.rs (limited to 'libhitomezashi/src') diff --git a/libhitomezashi/src/lib.rs b/libhitomezashi/src/lib.rs new file mode 100644 index 0000000..b07057a --- /dev/null +++ b/libhitomezashi/src/lib.rs @@ -0,0 +1,63 @@ +mod pixel_buffer; +pub use bitvec::vec::BitVec; +use pixel_buffer::PixelBuffer; + +pub fn get_hitomezashi_pattern( + x_pattern: BitVec, + y_pattern: BitVec, + gap: usize, + line_thickness: usize, +) -> PixelBuffer { + let mut buf = PixelBuffer::new(x_pattern.len() * gap, y_pattern.len() * gap); + // Draw y pattern (horizontal) lines + for i in 0..y_pattern.len() { + for j in 0..x_pattern.len() { + if (j % 2 != 0) == y_pattern[i] { + let x = j * gap; + let y = i * gap; + let width = gap; + let height = line_thickness; + buf.fill_rect(x, y, width, height); + } + } + } + // Draw x pattern (vertical) lines + for i in 0..x_pattern.len() { + for j in 0..y_pattern.len() { + if (j % 2 != 0) == x_pattern[i] { + let x = i * gap; + let y = j * gap; + let width = line_thickness; + let height = gap; + buf.fill_rect(x, y, width, height) + } + } + } + + // Join up the lines to avoid leaving holes at the intersections + // The best way to understand how this works is to try commenting it out + for x in (gap..buf.width).step_by(gap) { + for y in (gap..buf.height).step_by(gap) { + let width = line_thickness; + let height = line_thickness; + buf.fill_rect(x, y, width, height); + } + } + buf +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let mut x_pattern = BitVec::new(); + x_pattern.resize(40, false); + x_pattern.set(1, true); + let mut y_pattern = BitVec::new(); + y_pattern.resize(40, false); + y_pattern.set(1, true); + println!("{}", get_hitomezashi_pattern(x_pattern, y_pattern, 3, 1)); + } +} diff --git a/libhitomezashi/src/pixel_buffer.rs b/libhitomezashi/src/pixel_buffer.rs new file mode 100644 index 0000000..b151906 --- /dev/null +++ b/libhitomezashi/src/pixel_buffer.rs @@ -0,0 +1,93 @@ +use bitvec::prelude::*; +use std::fmt; +use std::ops::{Index, IndexMut}; + +/// 2D buffer of monochrome (white/black i.e. true/false) pixels +pub struct PixelBuffer { + buffer: BitVec, + pub width: usize, + pub height: usize, +} + +impl PixelBuffer { + pub fn new(width: usize, height: usize) -> Self { + let mut buffer = BitVec::with_capacity(width * height); + buffer.resize(width * height, false); + PixelBuffer { + buffer, + width, + height, + } + } + pub fn fill_rect(&mut self, x: usize, y: usize, width: usize, height: usize) { + for i in x..(x + width) { + for j in y..(y + height) { + self[i].set(j, true); + } + } + } +} + +impl Index for PixelBuffer { + type Output = BitSlice; + + fn index(&self, column: usize) -> &Self::Output { + &self.buffer[(column * self.height)..((column + 1) * self.height)] + } +} + +impl IndexMut for PixelBuffer { + fn index_mut(&mut self, column: usize) -> &mut Self::Output { + &mut self.buffer[(column * self.height)..((column + 1) * self.height)] + } +} + +impl fmt::Display for PixelBuffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut result = String::new(); + for y in 0..self.height { + for x in 0..self.width { + result.push(if self[x][y] { '1' } else { '0' }) + } + result.push('\n') + } + write!(f, "{}", result) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn access_default() { + let pixel_buffer = PixelBuffer::new(2, 3); + assert!(pixel_buffer[0][0] == false); + } + #[test] + fn mutate() { + let mut pixel_buffer = PixelBuffer::new(2, 3); + pixel_buffer[1].set(2, true); + assert!(pixel_buffer[1][2] == true); + } + #[test] + #[should_panic] + fn access_out_of_bounds() { + let pixel_buffer = PixelBuffer::new(10, 20); + assert!(pixel_buffer[10][0] == false); + } + #[test] + fn print() { + let mut pixel_buffer = PixelBuffer::new(3, 3); + pixel_buffer[1].set(1, true); + let result = format!("{}", pixel_buffer); + assert!(result == "000\n010\n000\n"); + } + #[test] + fn rect() { + let mut pixel_buffer = PixelBuffer::new(5, 3); + pixel_buffer.fill_rect(1, 0, 2, 2); + let result = format!("{}", pixel_buffer); + assert!(result == "01100\n01100\n00000\n"); + } +} -- cgit v1.2.3-57-g22cb