|
|
@ -38,25 +38,13 @@ namespace {
|
|
|
|
int x, y;
|
|
|
|
int x, y;
|
|
|
|
constexpr int2 (int _x, int _y) : x(_x), y(_y) {}
|
|
|
|
constexpr int2 (int _x, int _y) : x(_x), y(_y) {}
|
|
|
|
int2 (const int2& o) : x(o.x), y(o.y) {}
|
|
|
|
int2 (const int2& o) : x(o.x), y(o.y) {}
|
|
|
|
|
|
|
|
void operator+=(const int2 o) { x += o.x; y += o.y; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// void stepX() { ++x; }
|
|
|
|
|
|
|
|
// void stepY() { ++y; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
int2 operator+(const int2& a, const int2& b) { return int2(a.x+b.x, a.y+b.y); }
|
|
|
|
int2 operator+(const int2& a, const int2& b) { return int2(a.x+b.x, a.y+b.y); }
|
|
|
|
float2 operator+(const float2& f, const int2& i) { return float2(f.x+i.x, f.y+i.y); }
|
|
|
|
float2 operator+(const float2& f, const int2& i) { return float2(f.x+i.x, f.y+i.y); }
|
|
|
|
|
|
|
|
|
|
|
|
inline int getMaskAt(const std::vector< MarchingSquares::CellType >& cells, int width, int2 point) {
|
|
|
|
|
|
|
|
const int x = point.x;
|
|
|
|
|
|
|
|
const int y = point.y;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const MarchingSquares::CellType quad[4] = {
|
|
|
|
|
|
|
|
cells[(y-1) * width + (x-1)], cells[(y-1) * width + x], // TL T
|
|
|
|
|
|
|
|
cells[ y * width + (x-1)], cells[ y * width + x] }; // R X
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int mask = ((quad[0] == MarchingSquares::FREE) ? 0x0 : 0x1)
|
|
|
|
|
|
|
|
| ((quad[1] == MarchingSquares::FREE) ? 0x0 : 0x2)
|
|
|
|
|
|
|
|
| ((quad[2] == MarchingSquares::FREE) ? 0x0 : 0x4)
|
|
|
|
|
|
|
|
| ((quad[3] == MarchingSquares::FREE) ? 0x0 : 0x8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MarchingSquares::MarchingSquares()
|
|
|
|
MarchingSquares::MarchingSquares()
|
|
|
@ -86,14 +74,30 @@ void MarchingSquares::ReadImage(const std::string& filename)
|
|
|
|
if (x == 0 || x == width_ - 1 || y == 0 || y == height_ - 1)
|
|
|
|
if (x == 0 || x == width_ - 1 || y == 0 || y == height_ - 1)
|
|
|
|
c = SOLID;
|
|
|
|
c = SOLID;
|
|
|
|
|
|
|
|
|
|
|
|
// mark white cells sorrounded by 4 black cells as black
|
|
|
|
// mark white "hole" cells sorrounded by 4 black cells as black
|
|
|
|
|
|
|
|
if (y > 1 && y < height_-1 && x > 1 && x < width_-1 &&
|
|
|
|
|
|
|
|
image[y][x] >= 240 &&
|
|
|
|
|
|
|
|
image[y-1][x] < 240 &&
|
|
|
|
|
|
|
|
image[y+1][x] < 240 &&
|
|
|
|
|
|
|
|
image[y][x-1] < 240 &&
|
|
|
|
|
|
|
|
image[y][x+1] < 240)
|
|
|
|
|
|
|
|
c = SOLID;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// @note is it too much?
|
|
|
|
|
|
|
|
// mark black "lost" cells sorrounded by 4 white cells as white
|
|
|
|
// if (y > 1 && y < height_-1 && x > 1 && x < width_-1 &&
|
|
|
|
// if (y > 1 && y < height_-1 && x > 1 && x < width_-1 &&
|
|
|
|
// image[y-1][x] < 240 &&
|
|
|
|
// image[y][x] < 240 &&
|
|
|
|
// image[y+1][x] < 240 &&
|
|
|
|
// (image[y-1][x-1] >= 240 && image[y-1][x] >= 240 && image[y-1][x+1] >= 240 && image[y][x+1] >= 240 && image[y+1][x+1] >= 240 && image[y+1][x] >= 240 && image[y+1][x-1] >= 240 && image[y][x-1] >= 240))
|
|
|
|
// image[y][x-1] < 240 &&
|
|
|
|
// c = FREE;
|
|
|
|
// image[y][x+1] < 240)
|
|
|
|
|
|
|
|
// c = DESTROYABLE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // mark black "bump on the wall" cells as white
|
|
|
|
|
|
|
|
// if (y > 1 && y < height_-1 && x > 1 && x < width_-1 &&
|
|
|
|
|
|
|
|
// image[y][x] < 240 &&
|
|
|
|
|
|
|
|
// ((image[y-1][x-1] < 240 && image[y-1][x] < 240 && image[y-1][x+1] < 240 && image[y][x+1] >= 240 && image[y+1][x+1] >= 240 && image[y+1][x] >= 240 && image[y+1][x-1] >= 240 && image[y][x-1] >= 240) ||
|
|
|
|
|
|
|
|
// (image[y-1][x-1] >= 240 && image[y-1][x] >= 240 && image[y-1][x+1] < 240 && image[y][x+1] < 240 && image[y+1][x+1] < 240 && image[y+1][x] >= 240 && image[y+1][x-1] >= 240 && image[y][x-1] >= 240) ||
|
|
|
|
|
|
|
|
// (image[y-1][x-1] >= 240 && image[y-1][x] >= 240 && image[y-1][x+1] >= 240 && image[y][x+1] >= 240 && image[y+1][x+1] < 240 && image[y+1][x] < 240 && image[y+1][x-1] < 240 && image[y][x-1] >= 240) ||
|
|
|
|
|
|
|
|
// (image[y-1][x-1] < 240 && image[y-1][x] >= 240 && image[y-1][x+1] >= 240 && image[y][x+1] >= 240 && image[y+1][x+1] >= 240 && image[y+1][x] >= 240 && image[y+1][x-1] < 240 && image[y][x-1] < 240)))
|
|
|
|
|
|
|
|
// c = FREE;
|
|
|
|
|
|
|
|
|
|
|
|
cells_.push_back(c);
|
|
|
|
cells_.push_back(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -104,15 +108,14 @@ void MarchingSquares::ReadImage(const std::string& filename)
|
|
|
|
std::vector< std::pair<float2, float2> >
|
|
|
|
std::vector< std::pair<float2, float2> >
|
|
|
|
MarchingSquares::RunMarchingSquares() {
|
|
|
|
MarchingSquares::RunMarchingSquares() {
|
|
|
|
|
|
|
|
|
|
|
|
const int number_of_cells = width_*height_;
|
|
|
|
std::vector<bool> visited(width_*height_, false);
|
|
|
|
std::vector<bool> visited(number_of_cells, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector< std::pair<float2, float2> > lines;
|
|
|
|
std::vector< std::pair<float2, float2> > lines;
|
|
|
|
|
|
|
|
|
|
|
|
int2 point(1, 1);
|
|
|
|
int2 point(1, 1);
|
|
|
|
for (point.y = 1 ;point.y < height_; ++point.y) {
|
|
|
|
for (point.y = 1 ;point.y < height_; ++point.y) {
|
|
|
|
for (point.x = 1; point.x < width_; ++point.x) {
|
|
|
|
for (point.x = 1; point.x < width_; ++point.x) {
|
|
|
|
|
|
|
|
|
|
|
|
const int mask = getMaskAt(cells_, width_, point);
|
|
|
|
const int mask = getMaskAt(point.x, point.y);
|
|
|
|
|
|
|
|
|
|
|
|
Color::Modifier blue(Color::FG_BLUE);
|
|
|
|
Color::Modifier blue(Color::FG_BLUE);
|
|
|
|
Color::Modifier def(Color::FG_DEFAULT);
|
|
|
|
Color::Modifier def(Color::FG_DEFAULT);
|
|
|
@ -134,51 +137,82 @@ MarchingSquares::RunMarchingSquares() {
|
|
|
|
assert(mask != 10);
|
|
|
|
assert(mask != 10);
|
|
|
|
|
|
|
|
|
|
|
|
// cannot reach nonvisited bottomright corner
|
|
|
|
// cannot reach nonvisited bottomright corner
|
|
|
|
|
|
|
|
/// @note you can. the last is not visited
|
|
|
|
// assert(mask != 1);
|
|
|
|
// assert(mask != 1);
|
|
|
|
// assert(mask != 14);
|
|
|
|
// assert(mask != 14);
|
|
|
|
|
|
|
|
|
|
|
|
if (mask == 0x7 || mask == 0x2 || mask == 0x8 || mask == 0xd || mask == 0x6 || mask == 0x9) {
|
|
|
|
visitPoint(point.x, point.y, mask, visited, lines);
|
|
|
|
int2 i = point;
|
|
|
|
}
|
|
|
|
int counter = 0;
|
|
|
|
std::cout << std::endl;
|
|
|
|
while (true) {
|
|
|
|
}
|
|
|
|
int2 n = int2(i.x + 1, i.y);
|
|
|
|
|
|
|
|
int next_mask = getMaskAt(cells_, width_, n);
|
|
|
|
return lines;
|
|
|
|
if (n.x < width_ && point.y < height_ &&
|
|
|
|
|
|
|
|
( ((mask == 0x7 || mask == 0x2 || mask == 0x6) && next_mask == 0x3) ||
|
|
|
|
|
|
|
|
((mask == 0x8 || mask == 0xd || mask == 0x9) && next_mask == 0xc)) &&
|
|
|
|
|
|
|
|
visited[n.y*width_ + n.x] == false) {
|
|
|
|
|
|
|
|
visited[n.y*width_ + n.x] = true;
|
|
|
|
|
|
|
|
i = n;
|
|
|
|
|
|
|
|
++counter;
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lines.push_back(std::pair<float2, float2>(float2(point.x, point.y), float2( i.x + 1, i.y)));
|
|
|
|
|
|
|
|
|
|
|
|
int MarchingSquares::getMaskAt(int x, int y) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const CellType quad[4] = {
|
|
|
|
|
|
|
|
cells_[(y-1) * width_ + (x-1)], cells_[(y-1) * width_ + x], // TL T
|
|
|
|
|
|
|
|
cells_[ y * width_ + (x-1)], cells_[ y * width_ + x] }; // R X
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int mask = ((quad[0] == FREE) ? 0x0 : 0x1)
|
|
|
|
|
|
|
|
| ((quad[1] == FREE) ? 0x0 : 0x2)
|
|
|
|
|
|
|
|
| ((quad[2] == FREE) ? 0x0 : 0x4)
|
|
|
|
|
|
|
|
| ((quad[3] == FREE) ? 0x0 : 0x8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (mask == 0x7 || mask == 0xb || mask == 0x4 || mask == 0x8 || mask == 0x6 || mask == 0x9) {
|
|
|
|
void MarchingSquares::visitPoint(int x, int y, int mask, std::vector< bool >& visited, std::vector< std::pair<float2, float2> >& lines) const
|
|
|
|
int2 i = point;
|
|
|
|
{
|
|
|
|
int counter = 0;
|
|
|
|
visited[y*width_ + x] = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const bool horizontal_top = (mask == 0x7 || mask == 0x2 || mask == 0x6);
|
|
|
|
|
|
|
|
const bool horizontal_bottom = (mask == 0x8 || mask == 0x9 || mask == 0xd);
|
|
|
|
|
|
|
|
const bool vertical_left = (mask == 0x7 || mask == 0x4 || mask == 0x6);
|
|
|
|
|
|
|
|
const bool vertical_right = (mask == 0x8 || mask == 0x9 || mask == 0xb);
|
|
|
|
|
|
|
|
const bool horizontal = horizontal_top || horizontal_bottom;
|
|
|
|
|
|
|
|
const bool vertical = vertical_left || vertical_right;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!horizontal && !vertical)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
// assert(horizontal || vertical);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// const bool start_2_lines = (mask == 0x7 || mask == 0x6 || mask == 0x8 || mask == 0x9);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (horizontal) {
|
|
|
|
|
|
|
|
int2 i(x, y);
|
|
|
|
while (true) {
|
|
|
|
while (true) {
|
|
|
|
int2 n = int2(i.x, i.y + 1);
|
|
|
|
i += int2(1, 0);
|
|
|
|
int next_mask = getMaskAt(cells_, width_, n);
|
|
|
|
int next_mask = getMaskAt(i.x, i.y);
|
|
|
|
if (n.x < width_ && point.y < height_ &&
|
|
|
|
if (i.x < width_ && i.y < height_ &&
|
|
|
|
( ((mask == 0x7 || mask == 0x4 || mask == 0x6) && next_mask == 0x5) ||
|
|
|
|
( (horizontal_top && next_mask == 0x3) ||
|
|
|
|
((mask == 0xb || mask == 0x8 || mask == 0x9) && next_mask == 0xa)) &&
|
|
|
|
(horizontal_bottom && next_mask == 0xc) ||
|
|
|
|
visited[n.y*width_ + n.x] == false) {
|
|
|
|
(vertical_left && next_mask == 0x5) ||
|
|
|
|
visited[n.y*width_ + n.x] = true;
|
|
|
|
(vertical_right && next_mask == 0xa) ) &&
|
|
|
|
i = n;
|
|
|
|
visited[i.y*width_ + i.x] == false)
|
|
|
|
++counter;
|
|
|
|
visited[i.y*width_ + i.x] = true;
|
|
|
|
} else
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lines.push_back(std::pair<float2, float2>(float2(point.x, point.y), float2( i.x, i.y + 1)));
|
|
|
|
lines.push_back(std::pair<float2, float2>(float2(x, y), float2( i.x, i.y)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
visited[point.y*width_ + point.x] = true;
|
|
|
|
if (vertical) {
|
|
|
|
|
|
|
|
int2 i(x, y);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
|
|
i += int2(0, 1);
|
|
|
|
|
|
|
|
int next_mask = getMaskAt(i.x, i.y);
|
|
|
|
|
|
|
|
if (i.x < width_ && i.y < height_ &&
|
|
|
|
|
|
|
|
( (horizontal_top && next_mask == 0x3) ||
|
|
|
|
|
|
|
|
(horizontal_bottom && next_mask == 0xc) ||
|
|
|
|
|
|
|
|
(vertical_left && next_mask == 0x5) ||
|
|
|
|
|
|
|
|
(vertical_right && next_mask == 0xa) ) &&
|
|
|
|
|
|
|
|
visited[i.y*width_ + i.x] == false)
|
|
|
|
|
|
|
|
visited[i.y*width_ + i.x] = true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
|
|
lines.push_back(std::pair<float2, float2>(float2(x, y), float2( i.x, i.y)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return lines;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|