35 absl::Span<const RectangleInRange> non_fixed_boxes,
36 std::vector<Rectangle>* fixed_boxes) {
42 IntegerValue original_area = 0;
43 std::vector<Rectangle> fixed_boxes_copy;
45 for (
const Rectangle& r : *fixed_boxes) {
46 original_area += r.Area();
50 fixed_boxes_copy = *fixed_boxes;
53 const int original_num_boxes = fixed_boxes->size();
54 IntegerValue min_x_size = std::numeric_limits<IntegerValue>::max();
55 IntegerValue min_y_size = std::numeric_limits<IntegerValue>::max();
57 CHECK(!non_fixed_boxes.empty());
58 Rectangle bounding_box = non_fixed_boxes[0].bounding_area;
61 bounding_box.GrowToInclude(box.bounding_area);
62 min_x_size = std::min(min_x_size, box.x_size);
63 min_y_size = std::min(min_y_size, box.y_size);
70 while (new_size < fixed_boxes->
size()) {
71 Rectangle& rectangle = (*fixed_boxes)[new_size];
72 if (rectangle.x_min < bounding_box.x_min) {
73 rectangle.x_min = bounding_box.x_min;
76 if (rectangle.x_max > bounding_box.x_max) {
77 rectangle.x_max = bounding_box.x_max;
80 if (rectangle.y_min < bounding_box.y_min) {
81 rectangle.y_min = bounding_box.y_min;
84 if (rectangle.y_max > bounding_box.y_max) {
85 rectangle.y_max = bounding_box.y_max;
88 if (rectangle.SizeX() <= 0 || rectangle.SizeY() <= 0) {
90 std::swap(rectangle, (*fixed_boxes)[fixed_boxes->size() - 1]);
91 fixed_boxes->resize(fixed_boxes->size() - 1);
98 std::vector<Rectangle> optional_boxes = *fixed_boxes;
100 if (bounding_box.x_min > std::numeric_limits<IntegerValue>::min() &&
101 bounding_box.y_min > std::numeric_limits<IntegerValue>::min() &&
102 bounding_box.x_max < std::numeric_limits<IntegerValue>::max() &&
103 bounding_box.y_max < std::numeric_limits<IntegerValue>::max()) {
111 optional_boxes.push_back({.x_min = bounding_box.x_min - 1,
112 .x_max = bounding_box.x_max,
113 .y_min = bounding_box.y_min - 1,
114 .y_max = bounding_box.y_min});
115 optional_boxes.push_back({.x_min = bounding_box.x_max,
116 .x_max = bounding_box.x_max + 1,
117 .y_min = bounding_box.y_min - 1,
118 .y_max = bounding_box.y_max});
119 optional_boxes.push_back({.x_min = bounding_box.x_min,
120 .x_max = bounding_box.x_max + 1,
121 .y_min = bounding_box.y_max,
122 .y_max = bounding_box.y_max + 1});
123 optional_boxes.push_back({.x_min = bounding_box.x_min - 1,
124 .x_max = bounding_box.x_min,
125 .y_min = bounding_box.y_min,
126 .y_max = bounding_box.y_max + 1});
132 const int num_optional_boxes_to_remove = optional_boxes.size();
136 const auto add_box = [&optional_boxes](Rectangle new_box) {
137 std::vector<Rectangle> to_add = {std::move(new_box)};
138 for (
int i = 0;
i < to_add.size(); ++
i) {
139 Rectangle new_box = to_add[
i];
140 bool is_disjoint =
true;
141 for (
const Rectangle& existing_box : optional_boxes) {
142 if (!new_box.IsDisjoint(existing_box)) {
144 for (
const Rectangle& disjoint_box :
145 new_box.SetDifference(existing_box)) {
146 to_add.push_back(disjoint_box);
152 optional_boxes.push_back(std::move(new_box));
159 std::vector<Rectangle> bounding_boxes;
160 bounding_boxes.reserve(non_fixed_boxes.size());
162 bounding_boxes.push_back(box.bounding_area);
164 std::vector<Rectangle> empty_spaces =
166 for (
const Rectangle& r : empty_spaces) {
171 for (
int i = 1;
i < optional_boxes.size(); ++
i) {
172 const Rectangle cur_box = optional_boxes[
i];
173 for (
int j = 0; j <
i; ++j) {
174 const Rectangle& other_box = optional_boxes[j];
175 const IntegerValue lower_top = std::min(cur_box.y_max, other_box.y_max);
176 const IntegerValue higher_bottom =
177 std::max(other_box.y_min, cur_box.y_min);
178 const IntegerValue rightmost_left_edge =
179 std::max(other_box.x_min, cur_box.x_min);
180 const IntegerValue leftmost_right_edge =
181 std::min(other_box.x_max, cur_box.x_max);
182 if (rightmost_left_edge < leftmost_right_edge) {
183 if (lower_top < higher_bottom &&
184 higher_bottom - lower_top < min_y_size) {
185 add_box({.x_min = rightmost_left_edge,
186 .x_max = leftmost_right_edge,
188 .y_max = higher_bottom});
191 if (higher_bottom < lower_top) {
192 if (leftmost_right_edge < rightmost_left_edge &&
193 rightmost_left_edge - leftmost_right_edge < min_x_size) {
194 add_box({.x_min = leftmost_right_edge,
195 .x_max = rightmost_left_edge,
196 .y_min = higher_bottom,
197 .y_max = lower_top});
202 optional_boxes.erase(optional_boxes.begin(),
203 optional_boxes.begin() + num_optional_boxes_to_remove);
208 if (changed && VLOG_IS_ON(1)) {
209 IntegerValue area = 0;
210 for (
const Rectangle& r : *fixed_boxes) {
213 VLOG_EVERY_N_SEC(1, 1) <<
"Presolved " << original_num_boxes
214 <<
" fixed rectangles (area=" << original_area
215 <<
") into " << fixed_boxes->size()
216 <<
" (area=" << area <<
")";
218 VLOG_EVERY_N_SEC(2, 2) <<
"Presolved rectangles:\n"
219 <<
RenderDot(bounding_box, fixed_boxes_copy)
222 << (optional_boxes.empty()
224 : absl::StrCat(
"Unused optional rects:\n",
273 std::vector<Rectangle>* optional_rectangles) {
284 std::vector<std::unique_ptr<Rectangle>> rectangle_storage;
285 enum class OptionalEnum { OPTIONAL, MANDATORY };
287 std::vector<std::pair<const Rectangle*, OptionalEnum>> rectangles_ptr;
288 absl::flat_hash_map<Edge, int> top_edges_to_rectangle;
289 absl::flat_hash_map<Edge, int> bottom_edges_to_rectangle;
290 absl::flat_hash_map<Edge, int> left_edges_to_rectangle;
291 absl::flat_hash_map<Edge, int> right_edges_to_rectangle;
293 using EdgePosition = Edge::EdgePosition;
295 bool changed_optional =
false;
296 bool changed_mandatory =
false;
298 auto add_rectangle = [&](
const Rectangle* rectangle_ptr,
300 const int index = rectangles_ptr.size();
301 rectangles_ptr.push_back({rectangle_ptr,
optional});
302 const Rectangle& rectangle = *rectangles_ptr[
index].first;
303 top_edges_to_rectangle[Edge::GetEdge(rectangle, EdgePosition::TOP)] =
index;
304 bottom_edges_to_rectangle[Edge::GetEdge(rectangle, EdgePosition::BOTTOM)] =
306 left_edges_to_rectangle[Edge::GetEdge(rectangle, EdgePosition::LEFT)] =
308 right_edges_to_rectangle[Edge::GetEdge(rectangle, EdgePosition::RIGHT)] =
311 for (
const Rectangle& rectangle : *mandatory_rectangles) {
312 add_rectangle(&rectangle, OptionalEnum::MANDATORY);
314 for (
const Rectangle& rectangle : *optional_rectangles) {
315 add_rectangle(&rectangle, OptionalEnum::OPTIONAL);
318 auto remove_rectangle = [&](
const int index) {
319 const Rectangle& rectangle = *rectangles_ptr[
index].first;
320 const Edge top_edge = Edge::GetEdge(rectangle, EdgePosition::TOP);
321 const Edge bottom_edge = Edge::GetEdge(rectangle, EdgePosition::BOTTOM);
322 const Edge left_edge = Edge::GetEdge(rectangle, EdgePosition::LEFT);
323 const Edge right_edge = Edge::GetEdge(rectangle, EdgePosition::RIGHT);
324 top_edges_to_rectangle.erase(top_edge);
325 bottom_edges_to_rectangle.erase(bottom_edge);
326 left_edges_to_rectangle.erase(left_edge);
327 right_edges_to_rectangle.erase(right_edge);
328 rectangles_ptr[
index].first =
nullptr;
331 bool iteration_did_merge =
true;
332 while (iteration_did_merge) {
333 iteration_did_merge =
false;
334 for (
int i = 0;
i < rectangles_ptr.size(); ++
i) {
335 if (!rectangles_ptr[
i].first) {
338 const Rectangle& rectangle = *rectangles_ptr[
i].first;
340 const Edge top_edge = Edge::GetEdge(rectangle, EdgePosition::TOP);
341 const Edge bottom_edge = Edge::GetEdge(rectangle, EdgePosition::BOTTOM);
342 const Edge left_edge = Edge::GetEdge(rectangle, EdgePosition::LEFT);
343 const Edge right_edge = Edge::GetEdge(rectangle, EdgePosition::RIGHT);
346 if (
const auto it = right_edges_to_rectangle.find(left_edge);
347 it != right_edges_to_rectangle.end()) {
349 }
else if (
const auto it = left_edges_to_rectangle.find(right_edge);
350 it != left_edges_to_rectangle.end()) {
352 }
else if (
const auto it = bottom_edges_to_rectangle.find(top_edge);
353 it != bottom_edges_to_rectangle.end()) {
355 }
else if (
const auto it = top_edges_to_rectangle.find(bottom_edge);
356 it != top_edges_to_rectangle.end()) {
362 iteration_did_merge =
true;
365 const OptionalEnum new_optional =
366 (rectangles_ptr[
i].second == OptionalEnum::MANDATORY ||
367 rectangles_ptr[
index].second == OptionalEnum::MANDATORY)
368 ? OptionalEnum::MANDATORY
369 : OptionalEnum::OPTIONAL;
371 changed_mandatory || (new_optional == OptionalEnum::MANDATORY);
374 (rectangles_ptr[
i].second == OptionalEnum::OPTIONAL ||
375 rectangles_ptr[
index].second == OptionalEnum::OPTIONAL);
376 rectangle_storage.push_back(std::make_unique<Rectangle>(rectangle));
377 Rectangle& new_rectangle = *rectangle_storage.back();
378 new_rectangle.GrowToInclude(*rectangles_ptr[
index].first);
380 remove_rectangle(
index);
381 add_rectangle(&new_rectangle, new_optional);
385 if (changed_mandatory) {
386 std::vector<Rectangle> new_rectangles;
387 for (
auto [rectangle,
optional] : rectangles_ptr) {
388 if (rectangle &&
optional == OptionalEnum::MANDATORY) {
389 new_rectangles.push_back(*rectangle);
392 *mandatory_rectangles = std::move(new_rectangles);
394 if (changed_optional) {
395 std::vector<Rectangle> new_rectangles;
396 for (
auto [rectangle,
optional] : rectangles_ptr) {
397 if (rectangle &&
optional == OptionalEnum::OPTIONAL) {
398 new_rectangles.push_back(*rectangle);
401 *optional_rectangles = std::move(new_rectangles);
403 return changed_mandatory;