pixelset/cache/
mod.rs

1#[cfg(feature = "rand")]
2use rand::seq::IteratorRandom;
3#[cfg(feature = "rand")]
4use crate::cache::grow::grow_pixel_into_box;
5
6use crate::{PixelSet, shapes::{Rectangle, Shape}};
7
8pub mod grow;
9
10/// A high-performance spatial cache for `PixelSet` data, organized as a
11/// collection of `Rectangle` containers.
12///
13/// ## Overview
14///
15/// `PixelCache` is designed to store pixels in **spatially contiguous boxes**
16/// (`Rectangle`), making it easily to compactly store continuous sets of
17/// pixels.
18/// 
19/// A `PixelCache` can be very quickly iterated over, and converted to a
20/// `PixelSet`, but cannot be directly operated on, and generating one
21/// may take longer.
22#[derive(Clone)]
23pub struct PixelCache {
24    pub boxes: Vec<Rectangle>
25}
26
27impl PixelCache {
28    /// Creates a new empty `PixelCache`.
29    pub fn new() -> Self {
30        Self { boxes: vec![] }
31    }
32
33    /// Combines all cached `Rectangle` containers into a single, sorted `PixelSet`.
34    pub fn set(&self) -> PixelSet {
35        let mut pixels = Vec::with_capacity(self.len());
36        for rectangle in &self.boxes {
37            pixels.extend(rectangle.iter_pixels());
38        }
39
40        PixelSet::new(pixels)
41    }
42
43    /// Builds a `PixelCache` by repeatedly selecting **random pixels** from a
44    /// given `PixelSet` and expanding each into a `Rectangle`.
45    /// 
46    /// Creates a far more efficient and compact set than the original
47    /// `PixelSet`.
48    #[cfg(feature = "rand")]
49    pub fn generate_from_set(set: &PixelSet) -> Self {
50        let mut set = set.clone();
51        let mut rng = rand::rng();
52
53        let mut rectangles = vec![];
54        while set.len() > 0 {
55            let &pixel = set.iter().choose(&mut rng).unwrap();
56            let rectangle = grow_pixel_into_box(pixel, &set);
57            set = set.without(&rectangle.set());
58
59            rectangles.push(rectangle);
60        }
61
62        Self { boxes: rectangles }
63    }
64
65    /// Returns the total number of pixels contained across all cached boxes.
66    pub fn len(&self) -> usize {
67        self.boxes.iter()
68            .map(|rectangle| rectangle.len())
69            .sum()
70    }
71
72    /// Returns `true` if the cache contains no pixels.
73    pub fn is_empty(&self) -> bool {
74        self.len() == 0
75    }
76}