1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
extern crate coord_2d;
extern crate grid_2d;
extern crate image;
extern crate wfc;

use coord_2d::{Coord, Size};
use grid_2d::Grid;
use image::{DynamicImage, Rgb, RgbImage};
use wfc::overlapping::{OverlappingPatterns, Pattern};
use wfc::{GlobalStats, PatternId, Wave, WaveCellRef};

pub struct ImagePatterns {
    overlapping_patterns: OverlappingPatterns<Rgb<u8>>,
    empty_colour: Rgb<u8>,
}

impl ImagePatterns {
    pub fn new(image: &DynamicImage, pattern_size: Size) -> Self {
        let rgb_image = image.to_rgb();
        let size = Size::new(rgb_image.width(), rgb_image.height());
        let grid = Grid::new_fn(size, |Coord { x, y }| {
            *rgb_image.get_pixel(x as u32, y as u32)
        });
        let overlapping_patterns = OverlappingPatterns::new(grid, pattern_size);
        Self {
            overlapping_patterns,
            empty_colour: Rgb { data: [0, 0, 0] },
        }
    }

    pub fn set_empty_colour(&mut self, empty_colour: Rgb<u8>) {
        self.empty_colour = empty_colour;
    }

    pub fn to_image(&self) -> DynamicImage {
        let grid = self.overlapping_patterns.grid();
        let size = grid.size();
        let mut rgb_image = RgbImage::new(size.width(), size.height());
        for (Coord { x, y }, colour) in grid.enumerate() {
            rgb_image.put_pixel(x as u32, y as u32, *colour);
        }
        DynamicImage::ImageRgb8(rgb_image)
    }

    pub fn image_from_wave(&self, wave: &Wave) -> DynamicImage {
        let size = wave.grid().size();
        let mut rgb_image = RgbImage::new(size.width(), size.height());
        wave.grid().enumerate().for_each(|(Coord { x, y }, cell)| {
            let colour = match cell.chosen_pattern_id() {
                Ok(pattern_id) => {
                    *self.overlapping_patterns.pattern_top_left_value(pattern_id)
                }
                Err(_) => self.empty_colour,
            };
            rgb_image.put_pixel(x as u32, y as u32, colour);
        });
        DynamicImage::ImageRgb8(rgb_image)
    }

    pub fn weighted_average_colour<'a>(&self, cell: &'a WaveCellRef<'a>) -> Rgb<u8> {
        use wfc::EnumerateCompatiblePatternWeights::*;
        match cell.enumerate_compatible_pattern_weights() {
            MultipleCompatiblePatternsWithoutWeights | NoCompatiblePattern => {
                self.empty_colour
            }
            SingleCompatiblePatternWithoutWeight(pattern_id) => {
                *self.overlapping_patterns.pattern_top_left_value(pattern_id)
            }
            CompatiblePatternsWithWeights(iter) => {
                let (r, g, b) = iter
                    .map(|(pattern_id, weight)| {
                        let &Rgb { data: [r, g, b] } =
                            self.overlapping_patterns.pattern_top_left_value(pattern_id);
                        (r as u32 * weight, g as u32 * weight, b as u32 * weight)
                    })
                    .fold((0, 0, 0), |(acc_r, acc_g, acc_b), (r, g, b)| {
                        (acc_r + r, acc_g + g, acc_b + b)
                    });
                let total_weight = cell.sum_compatible_pattern_weight();
                Rgb {
                    data: [
                        (r / total_weight) as u8,
                        (g / total_weight) as u8,
                        (b / total_weight) as u8,
                    ],
                }
            }
        }
    }

    pub fn grid(&self) -> &Grid<Rgb<u8>> {
        self.overlapping_patterns.grid()
    }

    pub fn id_grid(&self) -> Grid<PatternId> {
        self.overlapping_patterns.id_grid()
    }

    pub fn pattern(&self, pattern_id: PatternId) -> &Pattern {
        self.overlapping_patterns.pattern(pattern_id)
    }

    pub fn pattern_mut(&mut self, pattern_id: PatternId) -> &mut Pattern {
        self.overlapping_patterns.pattern_mut(pattern_id)
    }

    pub fn global_stats(&self) -> GlobalStats {
        self.overlapping_patterns.global_stats()
    }
}