1use rand::distributions::{Distribution, Uniform, WeightedIndex};
2
3pub struct Space {
5 width: usize,
6 height: usize,
7 data: Vec<u8>
8}
9
10impl Space {
11 pub fn new(width: u32, height: u32) -> Self {
13 Self {
14 width: width as usize,
15 height: height as usize,
16 data: vec![0; (width * height) as usize]
17 }
18 }
19
20 pub fn width(&self) -> u32 {
22 self.width as u32
23 }
24
25 pub fn height(&self) -> u32 {
27 self.height as u32
28 }
29
30 pub fn fill_randomly(&mut self, density: u32) {
33 let mut rng = rand::thread_rng();
34 let rand_x = Uniform::from(0..self.width);
35 let rand_y = Uniform::from(0..self.height);
36
37 let weights = [755, 125, 90, 18, 6, 4, 2, 1];
38 let rand_z = WeightedIndex::new(&weights).expect("Failed to created intensity WeightedIndex");
39
40 let starcount = ((self.width as f32 / 100f32) * (self.height as f32/ 100f32) * density as f32) as usize;
41
42 for _ in 0..starcount {
43 self.draw_star(
44 rand_x.sample(&mut rng),
45 rand_y.sample(&mut rng),
46 rand_z.sample(&mut rng)
47 );
48 }
49 }
50
51 pub fn to_data(self) -> Vec<u8> {
54 self.data
55 }
56
57 fn draw_star(&mut self, x: usize, y: usize, intensity: usize) {
58 if intensity == 0 {
59 let index = y * self.width + x;
60
61 *self.data.get_mut(index).unwrap() = 255;
62 } else {
63 let clamp = |val: isize, low: usize, high: usize| -> usize {
64 if val < low as isize {
65 low
66 } else if val > high as isize {
67 high
68 } else {
69 val as usize
70 }
71 };
72
73 let x1 = x as isize - intensity as isize;
74 let y1 = y as isize - intensity as isize;
75 let x2 = x + intensity;
76 let y2 = y + intensity;
77
78 self.linex(y, clamp(x1, 0, self.width-1), clamp(x2 as isize, 0, self.width-1), 255);
80 self.liney(x,clamp(y1, 0, self.height-1), clamp(y2 as isize, 0, self.height-1), 255);
81
82 if intensity >= 2 {
84 let x1 = x as isize - (intensity/2) as isize;
85 let y1 = y as isize - (intensity/2) as isize;
86 let x2 = x + (intensity/2);
87 let y2 = y + (intensity/2);
88
89 self.line(
90 clamp(x1, 0, self.width-1),
91 clamp(y1, 0, self.height-1),
92 clamp(x2 as isize, 0, self.width-1),
93 clamp(y2 as isize, 0, self.height-1),
94 255
95 );
96
97 self.line(
98 clamp(x2 as isize, 0, self.width-1),
99 clamp(y1, 0, self.height-1),
100 clamp(x1, 0, self.width-1),
101 clamp(y2 as isize, 0, self.height-1),
102 255
103 );
104 }
105
106 *self.data.get_mut(y * self.width + x).unwrap() = 0;
108 }
109 }
110
111 fn linex(&mut self, y: usize, x1: usize, x2: usize, gray: u8) {
112 for x in x1..=x2 {
113 *self.data.get_mut(y * self.width + x).unwrap() = gray;
114 }
115 }
116
117 fn liney(&mut self, x: usize, y1: usize, y2: usize, gray: u8) {
118 for y in y1..=y2 {
119 *self.data.get_mut(y * self.width + x).unwrap() = gray;
120 }
121 }
122
123 fn line(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, gray: u8) {
124 let dx = x2 as isize - x1 as isize;
125 let dy = y2 as isize - y1 as isize;
126 let step = if dx.abs() > dy.abs() {
127 dx.abs()
128 } else {
129 dy.abs()
130 };
131
132 let dx = dx / step;
133 let dy = dy / step;
134 let mut x = x1 as isize;
135 let mut y = y1 as isize;
136 let mut i = 1;
137 loop {
138 if x > 0 && (x as usize) < self.width && y > 0 && (y as usize) < self.height {
139 *self.data.get_mut(y as usize * self.width + x as usize).unwrap() = gray;
140 }
141
142 if i > step {
143 break;
144 }
145
146 x = x + dx;
147 y = y + dy;
148 i += 1;
149 }
150 }
151}