diff --git a/radiantcore/patch/algorithm/General.cpp b/radiantcore/patch/algorithm/General.cpp index 1d485eeddc..ad3e9d2530 100644 --- a/radiantcore/patch/algorithm/General.cpp +++ b/radiantcore/patch/algorithm/General.cpp @@ -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; @@ -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 @@ -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()) { @@ -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 patch1Edges = { patch1FirstRow, patch1FirstCol, patch1LastRow, patch1LastCol }; + std::vector 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(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(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(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(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; @@ -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; @@ -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")); } diff --git a/test/PatchWelding.cpp b/test/PatchWelding.cpp index 0315b7a044..91447808e6 100644 --- a/test/PatchWelding.cpp +++ b/test/PatchWelding.cpp @@ -13,7 +13,7 @@ using PatchWeldingTest = RadiantTest; class PatchWelding3x3 : public PatchWeldingTest, - public testing::WithParamInterface + public testing::WithParamInterface> {}; namespace @@ -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)