Created
January 11, 2023 00:00
-
-
Save p0358/43d7de3c3490eb96eecef3d7155b3233 to your computer and use it in GitHub Desktop.
Given rectangular area with holes inside, constructs vector of reversed rectangles (ones that are outside of holes and cover the entirety of the remaining area). This algorithm can be used to for example draw some background around windows on the screen, without drawing over the windows.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <iostream> | |
#include <algorithm> | |
#include <vector> | |
#include <set> | |
class Rectangle { | |
public: | |
int x, y, w, h; | |
Rectangle() : x(0), y(0), w(0), h(0) {} | |
Rectangle(int X, int Y, int W, int H) : x(X), y(Y), w(W), h(H) {} | |
/*bool operator<(const Rectangle& other) const { | |
if (x != other.x) return x < other.x; | |
if (y != other.y) return y < other.y; | |
if (w != other.w) return w < other.w; | |
return h < other.h; | |
}*/ | |
}; | |
struct AvailableLine | |
{ | |
int ystart, yend; | |
}; | |
// It works by "scanning" the canvas from left to right, then making a list of available y lines in given x position (available = outside of holes). | |
// Then if any existing rectangle ends at previous x and its y-pos equals to one of available lines, we extent the rectangle by 1 to the right; | |
// otherwise, we create a new rectangle at current x, with initial y-pos and height being that of the new available line. | |
std::vector<Rectangle> getRemainingRectangles(const Rectangle& main_rect, const std::vector<Rectangle>& hole_rects) | |
{ | |
auto mx = main_rect.w; | |
auto my = main_rect.h; | |
std::vector<Rectangle> result{}; | |
std::vector<Rectangle> current_rects{}; | |
for (int x = 0; x < mx; x++) | |
{ | |
//current.x += 1; | |
std::vector<AvailableLine> lines{}; | |
AvailableLine current_line{ 0, 0 }; | |
for (int y = 0; y < my; y++) | |
{ | |
bool ok = true; | |
for (auto& hole : hole_rects) | |
{ | |
if (x >= hole.x && x < (hole.x + hole.w) && y >= hole.y && y < (hole.y + hole.h)) | |
{ | |
ok = false; | |
std::cout << "x:" << x << " y:" << y << | |
" is inside of hole x:" << hole.x << " y:" << hole.y << " w:" << hole.w << " h:" << hole.h << std::endl; | |
break; | |
} | |
} | |
if (ok) | |
current_line.yend++; | |
else | |
{ | |
if (current_line.ystart != current_line.yend) | |
lines.push_back(current_line); | |
current_line.ystart = std::min(y + 1, my); | |
current_line.yend = current_line.ystart; | |
std::cout << "Resetting current line at y:" << y << std::endl; | |
} | |
} | |
if (current_line.ystart != current_line.yend) | |
lines.push_back(current_line); | |
std::cout << "x: " << std::to_string(x) << std::endl; | |
for (auto& line : lines) | |
{ | |
std::cout << "line ystart:" << std::to_string(line.ystart) << " yend:" << std::to_string(line.yend) << std::endl; | |
} | |
/*for (auto& rect : current_rects) | |
{ | |
bool ok = false; | |
for (auto& line : lines) | |
{ | |
if (rect.y == line.ystart && (rect.y + rect.h) == line.yend) | |
{ | |
ok = true; | |
break; | |
} | |
} | |
if (!ok) | |
{ | |
// wrap this rectangle | |
} | |
}*/ | |
for (auto& line : lines) | |
{ | |
bool found = false; | |
for (auto& rect : current_rects) | |
{ | |
if (rect.y == line.ystart && (rect.y + rect.h) == line.yend && x - 1 == rect.x + rect.w - 1) | |
{ | |
found = true; | |
rect.w += 1; // extend this existing rectangle | |
break; | |
} | |
} | |
if (!found) | |
{ | |
// time to start a new rectangle | |
current_rects.push_back(Rectangle{ x, line.ystart, 1, line.yend - line.ystart }); | |
} | |
} | |
} | |
return current_rects; | |
} | |
int main() { | |
Rectangle main{0, 0, 1000, 1000}; | |
std::vector<Rectangle> smalls = { | |
{100, 100, 50, 50}, //{150, 100, 50, 50}, | |
{200, 200, 50, 50}, | |
{200, 180, 80, 80}, | |
//{100, 100, 50, 50}, {200, 200, 50, 50}, | |
}; | |
std::vector<Rectangle> rectangles = getRemainingRectangles(main, smalls); | |
std::cout << "Output size: " << std::to_string(rectangles.size()) << std::endl; | |
for (const Rectangle& rectangle : rectangles) { | |
std::cout << "x: " << rectangle.x << ", y: " << rectangle.y << ", w: " << rectangle.w << ", h: " << rectangle.h << std::endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment