Skip to content

Commit

Permalink
#5382: Edge detection code WIP, expanded unit test combinations.
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Dec 8, 2020
1 parent 26e68f3 commit 8fb5189
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 57 deletions.
158 changes: 111 additions & 47 deletions radiantcore/patch/algorithm/General.cpp
Expand Up @@ -433,7 +433,10 @@ inline bool isEqual(const PatchControlIterator& sequence1, const PatchControlIte
return false;
}

for (auto p1 = sequence1, p2 = sequence2; p1.isValid() && p2.isValid(); ++p1, ++p2)
auto p1 = sequence1;
auto p2 = sequence2;

for (; p1.isValid() && p2.isValid(); ++p1, ++p2)
{
rMessage() << "P1: " << p1->vertex << ", P2: " << p2->vertex << std::endl;

Expand All @@ -446,7 +449,8 @@ inline bool isEqual(const PatchControlIterator& sequence1, const PatchControlIte

rMessage() << "Sequences are equal" << std::endl;

return true;
// Sequences must be exhausted, otherwise we have different lengths
return !p1.isValid() && !p2.isValid();
}

// Copies all values from source to target, until the source sequence is depleted
Expand All @@ -467,11 +471,13 @@ scene::INodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNo
{
constexpr double WELD_EPSILON = 0.001;

#if 0
// Algorithm ported from ODRadiant https://svn.code.sf.net/p/odblur/code/code/OverDose%20Tools/ODRadiant/Patch.cpp) rev8348
int col, col1, col2;
int row, row1, row2;
int adj1, adj2;
bool match;
#endif

if (patchNode1->getParent() != patchNode2->getParent())
{
Expand All @@ -481,60 +487,117 @@ scene::INodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNo
auto& patch1 = patchNode1->getPatch();
auto& patch2 = patchNode2->getPatch();

if (patch1.getWidth() == patch2.getWidth())
// Construct an edge iterator for the first patch
SinglePatchRowIterator patch1FirstRow(patch1, 0);
SinglePatchColumnIterator patch1FirstCol(patch1, 0);
SinglePatchRowIterator patch1LastRow(patch1, patch1.getHeight() - 1);
SinglePatchColumnIterator patch1LastCol(patch1, patch1.getWidth() - 1);

// We'll be comparing each of these edges to all other four edges of the second patch
// and we're doing it in forward and backward iteration
SinglePatchRowIterator patch2FirstRow(patch2, 0);
SinglePatchColumnIterator patch2FirstCol(patch2, 0);
SinglePatchRowIterator patch2LastRow(patch2, patch2.getHeight() - 1);
SinglePatchColumnIterator patch2LastCol(patch2, patch2.getWidth() - 1);

SinglePatchRowReverseIterator patch2FirstRowReverse(patch2, 0);
SinglePatchColumnReverseIterator patch2FirstColReverse(patch2, 0);
SinglePatchRowReverseIterator patch2LastRowReverse(patch2, patch2.getHeight() - 1);
SinglePatchColumnReverseIterator patch2LastColReverse(patch2, patch2.getWidth() - 1);

std::vector<PatchControlIterator> patch1Edges = { patch1FirstRow, patch1FirstCol, patch1LastRow, patch1LastCol };
std::vector<PatchControlIterator> patch2Edges =
{
// Row dimensions match, compare the first and last row of this patch to the
// first and last row of the other patch
SinglePatchRowIterator patch1FirstRow(patch1, 0);
SinglePatchRowIterator patch1LastRow(patch1, patch1.getWidth() - 1);

SinglePatchRowIterator patch2FirstRow(patch2, 0);
SinglePatchRowIterator patch2LastRow(patch2, patch2.getWidth() - 1);

rMessage() << "Comparing P1FirstRow to P2FirstRow" << std::endl;
if (isEqual(patch1FirstRow, patch2FirstRow, WELD_EPSILON))
{
auto newPatchNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(newPatchNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);
patch2FirstRow, patch2FirstCol, patch2LastRow, patch2LastCol,
patch2FirstRowReverse, patch2FirstColReverse, patch2LastRowReverse, patch2LastColReverse
};

// prepend
// use rows of other patch
}

rMessage() << "Comparing P1FirstRow to P2LastRow" << std::endl;
if (isEqual(patch1FirstRow, patch2LastRow, WELD_EPSILON))
for (const auto& patch1Edge : patch1Edges)
{
for (const auto& patch2Edge : patch2Edges)
{
// prepend
// use rows of other patch from end
if (isEqual(patch1Edge, patch2Edge, WELD_EPSILON))
{
// Found a shared edge
rMessage() << "Found a shared edge" << std::endl;
}
}
}

rMessage() << "Comparing P1LastRow to P2FirstRow" << std::endl;
if (isEqual(patch1LastRow, patch2FirstRow, WELD_EPSILON))
{
auto sceneNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(sceneNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);
#if 0
rMessage() << "Comparing P1FirstRow to P2FirstRow" << std::endl;
if (isEqual(patch1FirstRow, patch2FirstRow, WELD_EPSILON))
{
auto newPatchNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(newPatchNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);

// prepend
// use rows of other patch
}

rMessage() << "Comparing P1FirstRow to P2FirstRowReverse" << std::endl;
if (isEqual(patch1FirstRow, patch2FirstRowReverse, WELD_EPSILON))
{
int i = 0;
}

rMessage() << "Comparing P1FirstRow to P2LastRow" << std::endl;
if (isEqual(patch1FirstRow, patch2LastRow, WELD_EPSILON))
{
int i = 0;
// prepend
// use rows of other patch from end
}

rMessage() << "Comparing P1FirstRow to P2LastRowReverse" << std::endl;
if (isEqual(patch1FirstRow, patch2LastRowReverse, WELD_EPSILON))
{
int i = 0;
}

rMessage() << "Comparing P1LastRow to P2FirstRow" << std::endl;
if (isEqual(patch1LastRow, patch2FirstRow, WELD_EPSILON))
{
auto sceneNode = GlobalPatchModule().createPatch(patch1.subdivisionsFixed() ? PatchDefType::Def3 : PatchDefType::Def2);
auto& newPatch = std::dynamic_pointer_cast<IPatchNode>(sceneNode)->getPatch();
newPatch.setDims(patch1.getWidth(), patch1.getHeight() + patch2.getHeight() - 1);

RowWisePatchIterator p1(patch1);
RowWisePatchIterator p2(patch2, 1, patch2.getWidth() - 1); // skip the first row of the second patch
RowWisePatchIterator target(newPatch);
RowWisePatchIterator p1(patch1);
RowWisePatchIterator p2(patch2, 1, patch2.getWidth() - 1); // skip the first row of the second patch
RowWisePatchIterator target(newPatch);

assignPatchControls(p1, target);
assignPatchControls(p2, target);
assignPatchControls(p1, target);
assignPatchControls(p2, target);

newPatch.controlPointsChanged();
newPatch.controlPointsChanged();

return sceneNode;
}
return sceneNode;
}

rMessage() << "Comparing P1LastRow to P2LastRow" << std::endl;
if (isEqual(patch1LastRow, patch2LastRow, WELD_EPSILON))
{
// append
// use rows of other patch from end
}
rMessage() << "Comparing P1LastRow to P2FirstRowReverse" << std::endl;
if (isEqual(patch1LastRow, patch2FirstRowReverse, WELD_EPSILON))
{
int i = 6;
}

rMessage() << "Comparing P1LastRow to P2LastRow" << std::endl;
if (isEqual(patch1LastRow, patch2LastRow, WELD_EPSILON))
{
int i = 0;
// append
// use rows of other patch from end
}

rMessage() << "Comparing P1LastRow to P2LastRowReverse" << std::endl;
if (isEqual(patch1LastRow, patch2LastRowReverse, WELD_EPSILON))
{
int i = 6;
}
#endif
#if 0
if (patch1.getWidth() == patch2.getWidth())
{
row1 = 0;
row2 = 0;

Expand Down Expand Up @@ -610,11 +673,12 @@ scene::INodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNo
break;
}
}
#endif
}
#endif

return scene::INodePtr();

#if 0
if (patch1.getWidth() == patch2.getHeight())
{
row1 = 0;
Expand Down Expand Up @@ -851,7 +915,7 @@ scene::INodePtr createdMergedPatch(const PatchNodePtr& patchNode1, const PatchNo
}
}
}

#endif
throw cmd::ExecutionFailure(_("Unable to weld patches, no suitable edges of same length found"));
}

Expand Down
63 changes: 53 additions & 10 deletions test/PatchWelding.cpp
Expand Up @@ -13,7 +13,7 @@ using PatchWeldingTest = RadiantTest;

class PatchWelding3x3 :
public PatchWeldingTest,
public testing::WithParamInterface<const char*>
public testing::WithParamInterface<std::tuple<const char*, const char*, int, int>>
{};

namespace
Expand Down Expand Up @@ -69,18 +69,61 @@ void assumePatchWeldingFails(const std::string& number1, const std::string& numb

}

// Patch 1 is sharing its first row with another patch
TEST_P(PatchWelding3x3, WeldPatch1WithOther3x3)
TEST_P(PatchWelding3x3, WeldWithOther3x3Patch)
{
loadMap("weld_patches2.mapx");

auto otherPatch = GetParam();

// Welding should produce a 5rows x 3cols patch
performPatchWeldingTest("1", otherPatch, 5, 3);
}

INSTANTIATE_TEST_CASE_P(WeldPatch1WithOther3x3, PatchWelding3x3, testing::Values("2", "3", "4", "5"));
auto firstPatch = std::get<0>(GetParam());
auto secondPatch = std::get<1>(GetParam());
auto expectedRows = std::get<2>(GetParam());
auto expectedColumns = std::get<3>(GetParam());

performPatchWeldingTest(firstPatch, secondPatch, expectedRows, expectedColumns);
}

// Patch 1 is sharing its first row
INSTANTIATE_TEST_CASE_P(WeldPatch1WithOther3x3, PatchWelding3x3,
testing::Values(std::tuple{ "1", "2", 5, 3 },
std::tuple{ "1", "3", 5, 3 },
std::tuple{ "1", "4", 5, 3 },
std::tuple{ "1", "5", 5, 3 },
std::tuple{ "2", "1", 1, 1 }, // TODO
std::tuple{ "3", "1", 1, 1 }, // TODO
std::tuple{ "4", "1", 1, 1 }, // TODO
std::tuple{ "5", "1", 1, 1 })); // TODO

// Patch 6 is sharing its last row
INSTANTIATE_TEST_CASE_P(WeldPatch6WithOther3x3, PatchWelding3x3,
testing::Values(std::tuple{ "6", "7", 5, 3 },
std::tuple{ "6", "8", 5, 3 },
std::tuple{ "6", "9", 5, 3 },
std::tuple{ "6", "10", 5, 3 },
std::tuple{ "7", "6", 1, 1 }, // TODO
std::tuple{ "8", "6", 1, 1 }, // TODO
std::tuple{ "9", "6", 1, 1 }, // TODO
std::tuple{ "10", "6", 1, 1 })); // TODO

// Patch 11 is sharing a column
INSTANTIATE_TEST_CASE_P(WeldPatch11WithOther3x3, PatchWelding3x3,
testing::Values(std::tuple{ "11", "12", 3, 5 },
std::tuple{ "11", "13", 3, 5 },
std::tuple{ "11", "14", 3, 5 },
std::tuple{ "11", "15", 3, 5 },
std::tuple{ "12", "11", 1, 1 }, // TODO
std::tuple{ "13", "11", 1, 1 }, // TODO
std::tuple{ "14", "11", 1, 1 }, // TODO
std::tuple{ "15", "11", 1, 1 })); // TODO

// Patch 16 is sharing a column
INSTANTIATE_TEST_CASE_P(WeldPatch16WithOther3x3, PatchWelding3x3,
testing::Values(std::tuple{ "16", "17", 3, 5 },
std::tuple{ "16", "18", 3, 5 },
std::tuple{ "16", "19", 3, 5 },
std::tuple{ "16", "20", 3, 5 },
std::tuple{ "17", "16", 1, 1 }, // TODO
std::tuple{ "18", "16", 1, 1 }, // TODO
std::tuple{ "19", "16", 1, 1 }, // TODO
std::tuple{ "20", "16", 1, 1 })); // TODO

#if 0
TEST_F(PatchWeldingTest, Weld3x3Patches1And5)
Expand Down

0 comments on commit 8fb5189

Please sign in to comment.