diff --git a/Cargo.lock b/Cargo.lock index 02569ab..4791066 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1922,5 +1922,6 @@ dependencies = [ "image", "itertools", "palette", + "rand", "serenity", ] diff --git a/Cargo.toml b/Cargo.toml index c529d3d..f99645b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ image = "*" palette = "*" serenity = "*" anyhow = "*" -itertools = "*" \ No newline at end of file +itertools = "*" +rand = "*" \ No newline at end of file diff --git a/src/wordcloud/hxbitmap.rs b/src/wordcloud/hxbitmap.rs index 816985a..20ad9f5 100644 --- a/src/wordcloud/hxbitmap.rs +++ b/src/wordcloud/hxbitmap.rs @@ -1,8 +1,9 @@ use std::{ops::{Shl, Shr}, fmt::Display, vec}; use anyhow::{Result, anyhow}; -use fontdue::Metrics; use itertools::{iproduct, enumerate}; -use super::util::{bits, next_multiple}; +use super::{util::{bits, next_multiple}, ring_reader::RingReader}; +use rand::thread_rng; +use rand::seq::SliceRandom; pub const CHARS: [&str; 2] = [" ", "█"]; // Horizontally Accelerated Bitmap #[derive(Clone)] @@ -16,14 +17,19 @@ pub struct HXBitmap { // _w/usize::BITS vec_w: usize, data: Vec, + // efficiently spreads content around + poses: RingReader<(usize, usize)> } impl HXBitmap { pub fn new(width: usize, height: usize) -> Self { let _w = next_multiple(width, usize::BITS as usize); let vec_w = _w/usize::BITS as usize; + let mut poses = Vec::from_iter(iproduct!(0..vec_w, 0..(height-3))); + poses.shuffle(&mut thread_rng()); Self { - width, height, _w, vec_w, data: vec![0; vec_w*height] + width, height, _w, vec_w, data: vec![0; vec_w*height], + poses: RingReader::new(poses) } } @@ -103,14 +109,17 @@ impl HXBitmap { )); } let others = other.h_offsets(); - for (vec_x, y) in iproduct!(0..(self.vec_w-other.vec_w), 0..(self.height-other.height)) { - for (dx, other) in enumerate(&others) { - if vec_x*usize::BITS as usize+dx >= self.width { - break; - } - if !self.overlaps(other, vec_x, y) { - self.add(other, vec_x, y); - return Ok((vec_x*usize::BITS as usize + dx, y)); + while let Some((vec_x, y)) = self.poses.next() { + if y+other.height < self.height { + for (dx, other) in enumerate(&others) { + if vec_x*usize::BITS as usize+dx >= self.width { + break; + } + if !self.overlaps(other, vec_x, y) { + self.add(other, vec_x, y); + self.poses.reset(); + return Ok((vec_x*usize::BITS as usize + dx, y)); + } } } } @@ -128,7 +137,8 @@ impl Shl for HXBitmap { height: self.height, _w: self._w, vec_w: self.vec_w, - data: self.data.into_iter().map(|v| v << rhs).collect() + data: self.data.into_iter().map(|v| v << rhs).collect(), + poses: self.poses.clone() } } } @@ -143,7 +153,8 @@ impl Shr for HXBitmap { height: self.height, _w: self._w, vec_w: self.vec_w, - data: self.data.into_iter().map(|v| v >> rhs).collect() + data: self.data.into_iter().map(|v| v >> rhs).collect(), + poses: self.poses.clone() } } } diff --git a/src/wordcloud/mod.rs b/src/wordcloud/mod.rs index 7b5207d..bb0b7f4 100644 --- a/src/wordcloud/mod.rs +++ b/src/wordcloud/mod.rs @@ -6,4 +6,5 @@ mod indexed_chars; mod text; mod image; mod rasterisable; +mod ring_reader; pub use wordcloud::{wordcloud, Token}; \ No newline at end of file diff --git a/src/wordcloud/ring_reader.rs b/src/wordcloud/ring_reader.rs new file mode 100644 index 0000000..f4c0d6c --- /dev/null +++ b/src/wordcloud/ring_reader.rs @@ -0,0 +1,36 @@ +#[derive(Clone)] +pub struct RingReader { + data: Vec, + start: usize, + end: usize, +} + +impl RingReader { + pub fn new(data: Vec) -> Self { + Self { + end: data.len(), + data: data, + start: 0 + } + } + + pub fn next(&mut self) -> Option { + if self.start == self.end { + return None + } + if self.start >= self.data.len() { + self.start = 0; + } + let res = self.data[self.start]; + self.start += 1; + Some(res) + } + + pub fn reset(&mut self) { + self.end = if self.start == 0 { + self.data.len() + } else { + self.start-1 + }; + } +} \ No newline at end of file