1use super::Packer;
2use crate::config::{MaxRectsHeuristic, PackerConfig};
3use crate::free_space::{prune_contained, subtract_intersections};
4use crate::geometry::{
5 PackingContext, PlacementGeometry, area_fit_score, bottom_ex_u32, contains_rect, intersects,
6 overlap_1d, right_ex_u32,
7};
8use crate::model::{Frame, Rect};
9
10pub struct MaxRectsPacker {
11 config: PackerConfig,
12 border: Rect,
13 free: Vec<Rect>,
14 used: Vec<Rect>,
15 heuristic: MaxRectsHeuristic,
16}
17
18impl MaxRectsPacker {
19 pub fn new(config: PackerConfig, heuristic: MaxRectsHeuristic) -> Self {
20 let border = PackingContext::new(&config).usable_area();
21 Self {
22 config,
23 border,
24 free: vec![border],
25 used: Vec::new(),
26 heuristic,
27 }
28 }
29
30 fn place_rect(&mut self, node: &Rect) {
31 if self.config.mr_reference {
32 return self.place_rect_ref(node);
33 }
34 self.free = subtract_intersections(self.free.iter().copied(), node);
35 self.prune_free_list();
36 self.used.push(*node);
37 }
38
39 fn place_rect_ref(&mut self, node: &Rect) {
40 let mut new_free: Vec<Rect> = Vec::new();
41 let mut i = 0usize;
42 while i < self.free.len() {
43 let fr = self.free[i];
44 if intersects(&fr, node) {
45 self.free.swap_remove(i);
47 self.split_free_node_ref(fr, node, &mut new_free);
48 } else {
49 i += 1;
50 }
51 }
52 self.prune_new_vs_old(&mut new_free);
54 self.prune_within(&mut new_free);
55 self.free.extend(new_free);
57 self.prune_free_list();
58 self.used.push(*node);
59 }
60
61 fn split_free_node_ref(&self, fr: Rect, node: &Rect, out: &mut Vec<Rect>) {
62 let fr_x2 = right_ex_u32(&fr);
63 let fr_y2 = bottom_ex_u32(&fr);
64 let n_x2 = right_ex_u32(node);
65 let n_y2 = bottom_ex_u32(node);
66
67 if node.x > fr.x && node.x < fr_x2 {
69 let w = node.x - fr.x;
70 out.push(Rect::new(fr.x, fr.y, w, fr.h));
71 }
72 if n_x2 < fr_x2 {
74 let x = n_x2;
75 let w = fr_x2 - n_x2;
76 out.push(Rect::new(x, fr.y, w, fr.h));
77 }
78 if node.y > fr.y && node.y < fr_y2 {
80 let h = node.y - fr.y;
81 out.push(Rect::new(fr.x, fr.y, fr.w, h));
82 }
83 if n_y2 < fr_y2 {
85 let y = n_y2;
86 let h = fr_y2 - n_y2;
87 out.push(Rect::new(fr.x, y, fr.w, h));
88 }
89 }
91
92 fn prune_new_vs_old(&mut self, new_free: &mut Vec<Rect>) {
93 new_free
95 .retain(|nr| !self.free.iter().any(|of| contains_rect(of, nr)) && nr.w > 0 && nr.h > 0);
96 let mut i = 0;
98 while i < self.free.len() {
99 if new_free.iter().any(|nr| contains_rect(nr, &self.free[i])) {
100 self.free.swap_remove(i);
101 } else {
102 i += 1;
103 }
104 }
105 }
106
107 fn prune_within(&self, v: &mut Vec<Rect>) {
108 let mut i = 0;
109 while i < v.len() {
110 let a = v[i];
111 let a_x2 = right_ex_u32(&a);
112 let a_y2 = bottom_ex_u32(&a);
113 let mut remove_i = false;
114 let mut j = 0;
115 while j < v.len() {
116 if i == j {
117 j += 1;
118 continue;
119 }
120 let b = v[j];
121 let b_x2 = right_ex_u32(&b);
122 let b_y2 = bottom_ex_u32(&b);
123 if a.x >= b.x && a.y >= b.y && a_x2 <= b_x2 && a_y2 <= b_y2 {
124 remove_i = true;
125 break;
126 }
127 j += 1;
128 }
129 if remove_i {
130 v.swap_remove(i);
131 } else {
132 i += 1;
133 }
134 }
135 }
136
137 fn prune_free_list(&mut self) {
138 prune_contained(&mut self.free);
139 }
140
141 fn score(&self, fr: &Rect, w: u32, h: u32) -> (i128, i128) {
142 let leftover_h = fr.w as i128 - w as i128;
143 let leftover_v = fr.h as i128 - h as i128;
144 let short_fit = leftover_h.abs().min(leftover_v.abs());
145 let long_fit = leftover_h.abs().max(leftover_v.abs());
146 let area_fit = area_fit_score(fr, w, h);
147 match self.heuristic {
148 MaxRectsHeuristic::BestAreaFit => (area_fit, short_fit),
149 MaxRectsHeuristic::BestShortSideFit => (short_fit, long_fit),
150 MaxRectsHeuristic::BestLongSideFit => (long_fit, short_fit),
151 MaxRectsHeuristic::BottomLeft => (fr.y as i128, fr.x as i128),
152 MaxRectsHeuristic::ContactPoint => {
153 let contact = self.contact_point_score(fr.x, fr.y, w, h);
155 (-(contact as i128), area_fit)
156 }
157 }
158 }
159
160 fn find_position(&self, w: u32, h: u32) -> Option<(Rect, bool)> {
161 let mut best_score1 = i128::MAX;
162 let mut best_score2 = i128::MAX;
163 let mut best_rect = Rect::new(0, 0, 0, 0);
164 let mut best_rot = false;
165 let mut best_top = u32::MAX; let mut best_left = u32::MAX; for fr in &self.free {
169 if fr.w >= w && fr.h >= h {
171 let (s1, s2) = self.score(fr, w, h);
172 let top = fr.y.saturating_add(h);
173 if s1 < best_score1
174 || (s1 == best_score1
175 && (s2 < best_score2
176 || (s2 == best_score2
177 && (top < best_top || (top == best_top && fr.x < best_left)))))
178 {
179 best_score1 = s1;
180 best_score2 = s2;
181 best_top = top;
182 best_left = fr.x;
183 best_rect = Rect::new(fr.x, fr.y, w, h);
184 best_rot = false;
185 }
186 if fr.w == w && fr.h == h {
188 return Some((Rect::new(fr.x, fr.y, w, h), false));
189 }
190 }
191 if self.config.allow_rotation && fr.w >= h && fr.h >= w {
193 let (s1, s2) = self.score(fr, h, w);
194 let top = fr.y.saturating_add(w);
195 if s1 < best_score1
196 || (s1 == best_score1
197 && (s2 < best_score2
198 || (s2 == best_score2
199 && (top < best_top || (top == best_top && fr.x < best_left)))))
200 {
201 best_score1 = s1;
202 best_score2 = s2;
203 best_top = top;
204 best_left = fr.x;
205 best_rect = Rect::new(fr.x, fr.y, h, w);
206 best_rot = true;
207 }
208 if fr.w == h && fr.h == w {
210 return Some((Rect::new(fr.x, fr.y, h, w), true));
211 }
212 }
213 }
214
215 if best_rect.w == 0 || best_rect.h == 0 {
216 None
217 } else {
218 Some((best_rect, best_rot))
219 }
220 }
221
222 fn contact_point_score(&self, x: u32, y: u32, w: u32, h: u32) -> u64 {
223 let node = Rect::new(x, y, w, h);
224 let mut score = 0u64;
225 let border_right = right_ex_u32(&self.border);
227 let border_bottom = bottom_ex_u32(&self.border);
228 if node.x == self.border.x {
229 score += node.h as u64;
230 }
231 if node.y == self.border.y {
232 score += node.w as u64;
233 }
234 if right_ex_u32(&node) == border_right {
235 score += node.h as u64;
236 }
237 if bottom_ex_u32(&node) == border_bottom {
238 score += node.w as u64;
239 }
240
241 for u in &self.used {
243 if node.x == right_ex_u32(u) || u.x == right_ex_u32(&node) {
245 let overlap = overlap_1d(node.y, bottom_ex_u32(&node), u.y, bottom_ex_u32(u));
246 score += overlap as u64;
247 }
248 if node.y == bottom_ex_u32(u) || u.y == bottom_ex_u32(&node) {
250 let overlap = overlap_1d(node.x, right_ex_u32(&node), u.x, right_ex_u32(u));
251 score += overlap as u64;
252 }
253 }
254 score
255 }
256
257 pub fn free_list_len(&self) -> usize {
258 self.free.len()
259 }
260}
261
262impl<K: Clone> Packer<K> for MaxRectsPacker {
263 fn can_pack(&self, rect: &Rect) -> bool {
264 let geometry = PlacementGeometry::new(rect, &self.config);
265 self.find_position(geometry.reserved_w, geometry.reserved_h)
266 .is_some()
267 }
268
269 fn pack(&mut self, key: K, rect: &Rect) -> Option<Frame<K>> {
270 let geometry = PlacementGeometry::new(rect, &self.config);
271 if let Some((place, rotated)) = self.find_position(geometry.reserved_w, geometry.reserved_h)
272 {
273 self.place_rect(&place);
274 Some(geometry.frame(key, *rect, &place, rotated))
275 } else {
276 None
277 }
278 }
279}