Commit 3d1a88c5 authored by LEFEBVREJP email's avatar LEFEBVREJP email
Browse files

#19. Rewrote marching squares algorithm to remove recursion and correct...

#19. Rewrote marching squares algorithm to remove recursion and correct clock-wise search of isovalue.
parent d51c1dec
Pipeline #13799 passed with stages
in 24 minutes and 40 seconds
...@@ -24,9 +24,6 @@ class MarchingSquares ...@@ -24,9 +24,6 @@ class MarchingSquares
std::vector<short> mBit; std::vector<short> mBit;
size_t mRows; size_t mRows;
size_t mColumns; size_t mColumns;
size_t depth;
size_t mLabel;
data_type mWashBit;
enum class StepDirection enum class StepDirection
{ {
...@@ -53,7 +50,8 @@ class MarchingSquares ...@@ -53,7 +50,8 @@ class MarchingSquares
*/ */
void step(size_t r, size_t c); void step(size_t r, size_t c);
bool accepts(size_t r, size_t c) const; bool accepts(size_t r, size_t c) const;
void clear_connected_component(int x, int y); void clear_connected_component(int row, int col, size_t label,
data_type wash_bit);
public: public:
/** /**
......
#include <array> #include <set>
#include <unordered_set>
#include <vector> #include <vector>
#include "radixalgorithm/marchingsquares.hh" #include "radixalgorithm/marchingsquares.hh"
...@@ -9,25 +8,46 @@ ...@@ -9,25 +8,46 @@
namespace radix namespace radix
{ {
template <typename data_type> template <typename data_type>
void MarchingSquares<data_type>::clear_connected_component(int x, int y) void MarchingSquares<data_type>::clear_connected_component(int row, int col,
size_t label,
data_type wash_bit)
{ {
if (x < 0 || x == mColumns) return; // out of bounds if (row < 0 || row == mColumns) return; // out of bounds
if (y < 0 || y == mRows) return; // out of bounds if (col < 0 || col == mRows) return; // out of bounds
depth++; std::set<size_t> list;
size_t c_i = mColumns * y + x; list.insert(mColumns * row + col);
if (mBit[c_i] == mLabel) while (!list.empty())
{ {
// clear the data const auto& it = list.begin();
size_t c_i = *it;
// update the row
row = c_i / mColumns;
// upate the column
col = c_i % mColumns;
// clear data
mBit[c_i] = 0; mBit[c_i] = 0;
mData[c_i] = mWashBit; mData[c_i] = wash_bit;
// search neighbors
for (int direction = 0; direction < 4; ++direction) for (int direction = 0; direction < 4; ++direction)
{ {
size_t nx = x + dx[direction]; size_t nc = col + dx[direction];
size_t ny = y + dy[direction]; size_t nr = row + dy[direction];
clear_connected_component(nx, ny); if (nc < 0 || nc == mColumns) continue; // out of bounds
if (nr < 0 || nr == mRows) continue; // out of bounds
size_t nc_i = mColumns * nr + nc;
if (mBit[nc_i] == label)
{
// if we already have this cell in the list to look at
// don't add it again
if (list.find(nc_i) == list.end())
{
list.insert(nc_i);
}
}
} }
list.erase(it);
} }
depth--;
} }
template <typename data_type> template <typename data_type>
...@@ -63,19 +83,22 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march( ...@@ -63,19 +83,22 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
mBit[p_i] = 2; mBit[p_i] = 2;
} }
} }
mWashBit = wash_bit;
mLabel = mBit[mColumns * start.first + start.second];
// //
// Walk the perimeter // Walk the perimeter
size_t row = start.first, column = start.second; size_t row = start.first, column = start.second;
radix_tagged_line("Starting (" << row << ", " << column << ")");
do do
{ {
step(row, column); step(row, column);
// If our current point is within our image // If our current point is within our image
// add it to the list of points // add it to the list of points
if (column >= 0 && column < mColumns && row >= 0 && row < mRows) // We have to allow for row and column being equal to the number
// of rows and columns to allow for traveling the boundaries
if (column >= 0 && column <= mColumns && row >= 0 && row <= mRows)
{ {
radix_tagged_line("(" << row << ", " << column
<< ") =" << int(next_step));
out.push_back({row, column}); out.push_back({row, column});
} }
...@@ -98,8 +121,9 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march( ...@@ -98,8 +121,9 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
} }
} while (row != start.first || column != start.second); } while (row != start.first || column != start.second);
depth = 0; clear_connected_component(start.first, start.second,
clear_connected_component(start.second, start.first); mBit[mColumns * start.first + start.second],
wash_bit);
return out; return out;
} // march } // march
...@@ -153,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c) ...@@ -153,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
if (u_left) state |= 1; if (u_left) state |= 1;
if (u_right) state |= 2; if (u_right) state |= 2;
if (l_left) state |= 4; if (l_right) state |= 4;
if (l_right) state |= 8; if (l_left) state |= 8;
// State now contains a number between 0 and 15 // State now contains a number between 0 and 15
// representing our state. // representing our state.
// In binary, it looks like 0000-1111 (in binary) // In binary, it looks like 0000-1111 (in binary)
...@@ -179,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c) ...@@ -179,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
switch (state) switch (state)
{ {
case 1: case 1:
next_step = StepDirection::Up; next_step = StepDirection::Left;
break; break;
case 2: case 2:
next_step = StepDirection::Right; if (prev_step == StepDirection::Left)
next_step = StepDirection::Up;
else
next_step = StepDirection::Right;
break; break;
case 3: case 3:
next_step = StepDirection::Right; next_step = StepDirection::Left;
break; break;
case 4: case 4:
next_step = StepDirection::Left; next_step = StepDirection::Right;
break; break;
case 5: case 5:
next_step = StepDirection::Up; next_step = StepDirection::Up;
break; break;
case 6: case 6:
if (prev_step == StepDirection::Up) if (prev_step == StepDirection::Down)
{ next_step = StepDirection::Down;
next_step = StepDirection::Left;
}
else else
{ next_step = StepDirection::Up;
next_step = StepDirection::Right;
}
break; break;
case 7: case 7:
next_step = StepDirection::Right; if (prev_step == StepDirection::Up)
next_step = StepDirection::Left;
else
next_step = StepDirection::Down;
break; break;
case 8: case 8:
next_step = StepDirection::Down; next_step = StepDirection::Down;
break; break;
case 9: case 9:
if (prev_step == StepDirection::Right) if (prev_step == StepDirection::Down)
{
next_step = StepDirection::Up;
}
else
{
next_step = StepDirection::Down; next_step = StepDirection::Down;
} else
next_step = StepDirection::Up;
break; break;
case 10: case 10:
next_step = StepDirection::Down; next_step = StepDirection::Down;
break; break;
case 11: case 11:
next_step = StepDirection::Down; if (prev_step == StepDirection::Left)
next_step = StepDirection::Down;
else
next_step = StepDirection::Right;
break; break;
case 12: case 12:
next_step = StepDirection::Left; next_step = StepDirection::Right;
break; break;
case 13: case 13:
next_step = StepDirection::Up; if (prev_step == StepDirection::Down)
next_step = StepDirection::Right;
else
next_step == StepDirection::Up;
break; break;
case 14: case 14:
next_step = StepDirection::Left; if (prev_step == StepDirection::Down)
next_step = StepDirection::Left;
else
next_step = StepDirection::Up;
break; break;
default: default:
next_step = StepDirection::None; next_step = StepDirection::None;
......
...@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple) ...@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple)
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2}, {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10}, {6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11}, {7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6}, {4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9}, {3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7}, {6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4}, {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{3, 4}, {2, 4}, {1, 4}, {1, 3}}; {5, 2}, {4, 2}, {3, 2}, {2, 2}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -77,15 +77,26 @@ TEST(MarchingSquares, TwoGroups) ...@@ -77,15 +77,26 @@ TEST(MarchingSquares, TwoGroups)
std::vector<std::pair<int, int>> first_contour = ms.march(2.); std::vector<std::pair<int, int>> first_contour = ms.march(2.);
std::vector<std::pair<int, int>> first_blessed{ std::vector<std::pair<int, int>> first_blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2}, {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10}, {6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11}, {7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6}, {4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9}, {3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7}, {6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4}, {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{3, 4}, {2, 4}, {1, 4}, {1, 3}}; {5, 2}, {4, 2}, {3, 2}, {2, 2}};
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < first_contour.size(); ++i)
// {
// const auto& pixel = first_contour[i];
// std::cout << "{" << pixel.first << "," << pixel.second << "}";
// if (i != first_contour.size() - 1)
// {
// std::cout << ",";
// }
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
ASSERT_EQ(first_blessed.size(), first_contour.size()); ASSERT_EQ(first_blessed.size(), first_contour.size());
for (size_t i = 0; i < first_blessed.size(); ++i) for (size_t i = 0; i < first_blessed.size(); ++i)
{ {
...@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups) ...@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups)
{ // get the second grouping { // get the second grouping
std::vector<std::pair<int, int>> second_contour = ms.march(2.); std::vector<std::pair<int, int>> second_contour = ms.march(2.);
// std::cout << "[ row , col ]" << std::endl; std::cout << "[ row , col ]" << std::endl;
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < second_contour.size(); ++i) // for (size_t i = 0; i < second_contour.size(); ++i)
// { // {
...@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups) ...@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> second_blessed{ std::vector<std::pair<int, int>> second_blessed{
{7, 16}, {8, 16}, {9, 16}, {9, 17}, {9, 18}, {8, 18}, {7, 18}, {7, 17}}; {7, 16}, {7, 17}, {7, 18}, {8, 18}, {9, 18}, {9, 17}, {9, 16}, {8, 16}};
ASSERT_EQ(second_blessed.size(), second_contour.size()); ASSERT_EQ(second_blessed.size(), second_contour.size());
for (size_t i = 0; i < second_blessed.size(); ++i) for (size_t i = 0; i < second_blessed.size(); ++i)
{ {
...@@ -154,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -154,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {8, 1}, {2, 0}, {2, 1}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2},
{8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {2, 1}}; {8, 2}, {8, 1}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -179,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -179,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl; // std::cout << std::endl;
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{6, 6}, {7, 6}, {8, 6}, {9, 6}, std::vector<std::pair<int, int>> blessed{
{9, 5}, {9, 4}, {9, 3}, {9, 8}, {6, 6}, {6, 7}, {6, 8}, {7, 8}, {8, 8}, {9, 8},
{8, 8}, {7, 8}, {6, 8}, {6, 7}}; {10, 8}, {10, 7}, {10, 6}, {10, 5}, {10, 4}, {10, 3},
{9, 3}, {9, 4}, {9, 5}, {9, 6}, {8, 6}, {7, 6}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -206,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -206,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{4, 18}, {5, 18}, {5, 17}, {6, 17}, {7, 17}, {8, 17}, {8, 18}, {4, 18}, {4, 19}, {4, 20}, {5, 20}, {6, 20}, {6, 19},
{9, 18}, {9, 19}, {8, 19}, {7, 19}, {6, 19}, {4, 19}}; {7, 19}, {8, 19}, {8, 20}, {9, 20}, {9, 19}, {9, 18},
{8, 18}, {8, 17}, {7, 17}, {6, 17}, {5, 17}, {5, 18}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -231,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -231,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl; // std::cout << std::endl;
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{0, 14}, {1, 14}, {2, 14}, {2, 15}, std::vector<std::pair<int, int>> blessed{{0, 14}, {0, 15}, {0, 16}, {0, 17},
{2, 16}, {2, 17}, {1, 17}, {0, 17}, {1, 17}, {2, 17}, {2, 16}, {2, 15},
{0, 16}, {0, 15}}; {2, 14}, {1, 14}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment