diff --git a/lib/qtgraph/marching_squares.cpp b/lib/qtgraph/marching_squares.cpp index 00a469d..4ea531c 100644 --- a/lib/qtgraph/marching_squares.cpp +++ b/lib/qtgraph/marching_squares.cpp @@ -38,25 +38,13 @@ namespace { int x, y; constexpr int2 (int _x, int _y) : x(_x), y(_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); } 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() @@ -86,14 +74,30 @@ void MarchingSquares::ReadImage(const std::string& filename) if (x == 0 || x == width_ - 1 || y == 0 || y == height_ - 1) 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 && -// image[y-1][x] < 240 && -// image[y+1][x] < 240 && -// image[y][x-1] < 240 && -// image[y][x+1] < 240) -// c = DESTROYABLE; +// 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)) +// c = FREE; +// // 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); } @@ -104,15 +108,14 @@ void MarchingSquares::ReadImage(const std::string& filename) std::vector< std::pair > MarchingSquares::RunMarchingSquares() { - const int number_of_cells = width_*height_; - std::vector visited(number_of_cells, false); - + std::vector visited(width_*height_, false); std::vector< std::pair > lines; + int2 point(1, 1); for (point.y = 1 ;point.y < height_; ++point.y) { 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 def(Color::FG_DEFAULT); @@ -134,51 +137,82 @@ MarchingSquares::RunMarchingSquares() { assert(mask != 10); // cannot reach nonvisited bottomright corner + /// @note you can. the last is not visited // assert(mask != 1); // assert(mask != 14); - if (mask == 0x7 || mask == 0x2 || mask == 0x8 || mask == 0xd || mask == 0x6 || mask == 0x9) { - int2 i = point; - int counter = 0; - while (true) { - int2 n = int2(i.x + 1, i.y); - int next_mask = getMaskAt(cells_, width_, n); - 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(point.x, point.y), float2( i.x + 1, i.y))); - } - - if (mask == 0x7 || mask == 0xb || mask == 0x4 || mask == 0x8 || mask == 0x6 || mask == 0x9) { - int2 i = point; - int counter = 0; - while (true) { - int2 n = int2(i.x, i.y + 1); - int next_mask = getMaskAt(cells_, width_, n); - if (n.x < width_ && point.y < height_ && - ( ((mask == 0x7 || mask == 0x4 || mask == 0x6) && next_mask == 0x5) || - ((mask == 0xb || mask == 0x8 || mask == 0x9) && next_mask == 0xa)) && - 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(point.x, point.y), float2( i.x, i.y + 1))); - } - - visited[point.y*width_ + point.x] = true; + visitPoint(point.x, point.y, mask, visited, lines); } std::cout << std::endl; } return lines; } + +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; +} + +void MarchingSquares::visitPoint(int x, int y, int mask, std::vector< bool >& visited, std::vector< std::pair >& lines) const +{ + 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) { + i += int2(1, 0); + 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; + } + lines.push_back(std::pair(float2(x, y), float2( i.x, i.y))); + } + + 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; + } + lines.push_back(std::pair(float2(x, y), float2( i.x, i.y))); + } +} diff --git a/lib/qtgraph/marching_squares.hpp b/lib/qtgraph/marching_squares.hpp index c3f8ec3..13e9985 100644 --- a/lib/qtgraph/marching_squares.hpp +++ b/lib/qtgraph/marching_squares.hpp @@ -17,6 +17,8 @@ public: std::vector< std::pair > RunMarchingSquares(); private: + int getMaskAt(int x, int y) const; + void visitPoint(int x, int y, int mask, std::vector& visited, std::vector< std::pair >& lines) const; std::size_t width_; std::size_t height_;