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
std::vector<short> mBit;
size_t mRows;
size_t mColumns;
size_t depth;
size_t mLabel;
data_type mWashBit;
enum class StepDirection
{
......@@ -53,7 +50,8 @@ class MarchingSquares
*/
void step(size_t r, size_t c);
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:
/**
......
#include <array>
#include <unordered_set>
#include <set>
#include <vector>
#include "radixalgorithm/marchingsquares.hh"
......@@ -9,25 +8,46 @@
namespace radix
{
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 (y < 0 || y == mRows) return; // out of bounds
depth++;
size_t c_i = mColumns * y + x;
if (mBit[c_i] == mLabel)
if (row < 0 || row == mColumns) return; // out of bounds
if (col < 0 || col == mRows) return; // out of bounds
std::set<size_t> list;
list.insert(mColumns * row + col);
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;
mData[c_i] = mWashBit;
mData[c_i] = wash_bit;
// search neighbors
for (int direction = 0; direction < 4; ++direction)
{
size_t nx = x + dx[direction];
size_t ny = y + dy[direction];
clear_connected_component(nx, ny);
size_t nc = col + dx[direction];
size_t nr = row + dy[direction];
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>
......@@ -63,19 +83,22 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
mBit[p_i] = 2;
}
}
mWashBit = wash_bit;
mLabel = mBit[mColumns * start.first + start.second];
//
// Walk the perimeter
size_t row = start.first, column = start.second;
radix_tagged_line("Starting (" << row << ", " << column << ")");
do
{
step(row, column);
// If our current point is within our image
// 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});
}
......@@ -98,8 +121,9 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
}
} while (row != start.first || column != start.second);
depth = 0;
clear_connected_component(start.second, start.first);
clear_connected_component(start.first, start.second,
mBit[mColumns * start.first + start.second],
wash_bit);
return out;
} // march
......@@ -153,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
if (u_left) state |= 1;
if (u_right) state |= 2;
if (l_left) state |= 4;
if (l_right) state |= 8;
if (l_right) state |= 4;
if (l_left) state |= 8;
// State now contains a number between 0 and 15
// representing our state.
// In binary, it looks like 0000-1111 (in binary)
......@@ -179,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
switch (state)
{
case 1:
next_step = StepDirection::Up;
next_step = StepDirection::Left;
break;
case 2:
next_step = StepDirection::Right;
if (prev_step == StepDirection::Left)
next_step = StepDirection::Up;
else
next_step = StepDirection::Right;
break;
case 3:
next_step = StepDirection::Right;
next_step = StepDirection::Left;
break;
case 4:
next_step = StepDirection::Left;
next_step = StepDirection::Right;
break;
case 5:
next_step = StepDirection::Up;
break;
case 6:
if (prev_step == StepDirection::Up)
{
next_step = StepDirection::Left;
}
if (prev_step == StepDirection::Down)
next_step = StepDirection::Down;
else
{
next_step = StepDirection::Right;
}
next_step = StepDirection::Up;
break;
case 7:
next_step = StepDirection::Right;
if (prev_step == StepDirection::Up)
next_step = StepDirection::Left;
else
next_step = StepDirection::Down;
break;
case 8:
next_step = StepDirection::Down;
break;
case 9:
if (prev_step == StepDirection::Right)
{
next_step = StepDirection::Up;
}
else
{
if (prev_step == StepDirection::Down)
next_step = StepDirection::Down;
}
else
next_step = StepDirection::Up;
break;
case 10:
next_step = StepDirection::Down;
break;
case 11:
next_step = StepDirection::Down;
if (prev_step == StepDirection::Left)
next_step = StepDirection::Down;
else
next_step = StepDirection::Right;
break;
case 12:
next_step = StepDirection::Left;
next_step = StepDirection::Right;
break;
case 13:
next_step = StepDirection::Up;
if (prev_step == StepDirection::Down)
next_step = StepDirection::Right;
else
next_step == StepDirection::Up;
break;
case 14:
next_step = StepDirection::Left;
if (prev_step == StepDirection::Down)
next_step = StepDirection::Left;
else
next_step = StepDirection::Up;
break;
default:
next_step = StepDirection::None;
......
......@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple)
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4},
{3, 4}, {2, 4}, {1, 4}, {1, 3}};
{1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{5, 2}, {4, 2}, {3, 2}, {2, 2}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -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_blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4},
{3, 4}, {2, 4}, {1, 4}, {1, 3}};
{1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{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());
for (size_t i = 0; i < first_blessed.size(); ++i)
{
......@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups)
{ // get the second grouping
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;
// for (size_t i = 0; i < second_contour.size(); ++i)
// {
......@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups)
// }
// std::cout << "}" << std::endl;
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());
for (size_t i = 0; i < second_blessed.size(); ++i)
{
......@@ -154,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups)
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {8, 1},
{8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {2, 1}};
{2, 0}, {2, 1}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2},
{8, 2}, {8, 1}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -179,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{6, 6}, {7, 6}, {8, 6}, {9, 6},
{9, 5}, {9, 4}, {9, 3}, {9, 8},
{8, 8}, {7, 8}, {6, 8}, {6, 7}};
std::vector<std::pair<int, int>> blessed{
{6, 6}, {6, 7}, {6, 8}, {7, 8}, {8, 8}, {9, 8},
{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());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -206,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{4, 18}, {5, 18}, {5, 17}, {6, 17}, {7, 17}, {8, 17}, {8, 18},
{9, 18}, {9, 19}, {8, 19}, {7, 19}, {6, 19}, {4, 19}};
{4, 18}, {4, 19}, {4, 20}, {5, 20}, {6, 20}, {6, 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());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -231,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{0, 14}, {1, 14}, {2, 14}, {2, 15},
{2, 16}, {2, 17}, {1, 17}, {0, 17},
{0, 16}, {0, 15}};
std::vector<std::pair<int, int>> blessed{{0, 14}, {0, 15}, {0, 16}, {0, 17},
{1, 17}, {2, 17}, {2, 16}, {2, 15},
{2, 14}, {1, 14}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......
Supports Markdown
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